Skip to content

let sampling return a vector of ParamsWithStats - #523

Draft
shravanngoswamii wants to merge 10 commits into
mainfrom
sg/params-with-stats
Draft

let sampling return a vector of ParamsWithStats#523
shravanngoswamii wants to merge 10 commits into
mainfrom
sg/params-with-stats

Conversation

@shravanngoswamii

@shravanngoswamii shravanngoswamii commented Jul 31, 2026

Copy link
Copy Markdown
Member

Adds chain_type = Vector{ParamsWithStats}: one entry per draw, params keyed by VarName so array variables stay whole, stats as the sampler reported them. AbstractMCMC.from_samples(Chains, reshape(draws, :, 1)) and the same with VNChain convert them.

Samplers now implement one method, transition_params_and_stats(model, sampler, transition), and all three output formats are built from it.

Other changes, breaking ones marked:

  • callbacks report VarName keys in the model's space for every sampler; with HMC, MH and slice they used to give unnamed θ[i] in unconstrained space (breaking: pws.params.mu -> pws.params[@varname(mu)])
  • Gibbs and IndependentMH chains carry lp; internals was empty before (breaking: one extra column)
  • a statistic a draw did not report is absent instead of padded (breaking: in VNChain it is missing, not NaN)
  • gen_chains takes one NamedTuple per draw, not a names list plus a values table (breaking)
  • MALA columns named after the model instead of param_1

One question. I used AbstractMCMC.ParamsWithStats directly. DynamicPPL instead defines its own ParamsWithStats and kept the AbstractMCMC one for callbacks only. Which do we want here? -- #523 (comment)

Each sampler now only implements transition_params_and_stats, so the chain
extensions stop duplicating the same unpacking per output format. Drops four
extensions and makes MCMCChains handle its own statistic flattening.
chain_type = Vector{ParamsWithStats} returns one entry per draw, keyed by
VarName so array-valued variables stay whole. Needs no extension since
AbstractMCMC is a hard dependency. The callback constructor now uses the same
VarName-keyed container instead of stringified symbols.
AbstractMCMC.from_samples takes a draws matrix, so a single run converts with
reshape(draws, :, 1).
@codecov

codecov Bot commented Jul 31, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.61745% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.81%. Comparing base (416590f) to head (7b9d516).

Files with missing lines Patch % Lines
JuliaBUGS/src/model/abstractmcmc.jl 94.91% 3 Missing ⚠️
JuliaBUGS/ext/JuliaBUGSAdvancedMHMCMCChainsExt.jl 50.00% 2 Missing ⚠️
JuliaBUGS/ext/JuliaBUGSMCMCChainsExt.jl 95.74% 2 Missing ⚠️
JuliaBUGS/src/JuliaBUGS.jl 66.66% 2 Missing ⚠️
JuliaBUGS/src/gibbs.jl 50.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #523      +/-   ##
==========================================
+ Coverage   87.79%   87.81%   +0.02%     
==========================================
  Files          34       32       -2     
  Lines        3679     3645      -34     
==========================================
- Hits         3230     3201      -29     
+ Misses        449      444       -5     
Flag Coverage Δ
callbacks 28.71% <24.83%> (+0.70%) ⬆️
compilation_model 39.46% <0.00%> (+0.36%) ⬆️
compilation_source_gen 44.00% <0.00%> (+0.41%) ⬆️
distributed_sampling 33.46% <0.00%> (+0.31%) ⬆️
elementary 26.76% <0.00%> (+0.24%) ⬆️
frontend 37.22% <0.00%> (+0.34%) ⬆️
gibbs 33.15% <24.16%> (+0.90%) ⬆️
graphs 21.08% <0.00%> (+0.19%) ⬆️
inference_chains 37.82% <59.06%> (+3.99%) ⬆️
inference_flexichains 42.17% <37.58%> (+1.15%) ⬆️
inference_hmc 26.54% <23.48%> (+0.90%) ⬆️
inference_marginalization 30.76% <23.48%> (+0.94%) ⬆️
inference_mh 26.95% <24.16%> (+0.85%) ⬆️
inference_slice_sampling 23.73% <34.89%> (-1.23%) ⬇️
log_density 55.46% <24.16%> (+1.12%) ⬆️
model_operations 43.45% <0.00%> (+0.40%) ⬆️
parallel_sampling 22.85% <23.48%> (+0.86%) ⬆️
serialization 31.47% <0.00%> (+0.29%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 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.

@github-actions

Copy link
Copy Markdown
Contributor

JuliaBUGS.jl documentation for PR #523 is available at:
https://TuringLang.github.io/JuliaBUGS.jl/previews/PR523/

A multivariate slice sampler reports num_proposals per coordinate, so converting
those draws hit an unconvertible array element.
transition_params_and_stats now unpacks one transition into (params, stats),
so a statistic a draw never reported stays absent rather than being padded with
NaN. Deletes the slice sampler's padding, lets Chains take the union of keys and
fill the gaps itself, and fixes MALA, whose GradientTransition the vector-shaped
extractor could not service.

The same method now drives the ParamsWithStats a callback sees, so HMC, MH and
slice callbacks report VarName-keyed parameters in the model's space instead of
falling through to unnamed theta[i] in the sampler's space.
…n non-numeric ones

Gibbs and IndependentMH chains had an empty internals section and no log
density at all. The evaluation that reconstructs each draw already computes it,
so lp now costs nothing and every output format carries it, which is what makes
the callback and the sampling output agree.

Also: only numeric arrays expand into scalar Chains columns, so a sampler
reporting anything else no longer breaks the conversion; array statistics are
copied like array parameters; environment recovery dispatches on the sampler
rather than guessing from the transition's shape; and from_samples(VNChain)
gained the start/thin that the Chains version already had.
@shravanngoswamii
shravanngoswamii marked this pull request as ready for review August 4, 2026 20:43
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Benchmark Results

Julia 1.11.9 on INTEL(R) XEON(R) PLATINUM 8573C (Linux)

Ratio = JuliaBUGS/Stan (lower is better for JuliaBUGS)

Model Stan Params JBUGS Params LD Ratio Grad Ratio
rats 65 65 0.27x 2.15x
pumps 12 12 0.56x 2.01x
bones 13 13 0.56x 3.25x
oxford 244 244 1.22x 3.96x
epil 303 303 0.32x 1.56x
lsat 1006 1006 0.47x 1.54x
schools 133 133 0.28x 2.05x
beetles 2 2 1.57x 4.98x
air 5 5 0.54x 2.37x

Note: Stan benchmarks use hand-optimized Stan models, not direct BUGS translations. Comparison is illustrative only.

@shravanngoswamii
shravanngoswamii marked this pull request as draft August 5, 2026 11:19
@shravanngoswamii

Copy link
Copy Markdown
Member Author

I forgot that it was already discussed to stay consistent with DynamicPPL -- approach here is not consistent so let me make the changes before asking for review again.

@shravanngoswamii

Copy link
Copy Markdown
Member Author

#517 and TuringLang/AbstractPPL.jl#178, both closed. TuringLang/AbstractMCMC.jl#212 landed, so the wrapper is there. The container is not.

this PR keeps OrderedDict{VarName,Any} in the params slot. Now, FlexiChains cannot read it directly, so I wrote from_samples for Chains and VNChain by hand. Those can be deleted if the container becomes VarNamedTuple.

Should I wait for TuringLang/AbstractPPL.jl#178, or keep this container and swap later? Making chain_type=Any return ParamsWithStats and rand return an of-type object are both independent of that, so I can do those either way.

@sunxd3 Can you help me understand things here like in what direction do we want to go here?

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.

1 participant