Skip to content

Conversation

penelopeysm
Copy link
Member

@penelopeysm penelopeysm commented Oct 15, 2025

This PR:

  • Reimplements the pointwise_logdensities family of functions using InitContext. NOTE They now return a MCMCChains.Chains by default rather than an OrderedDict, see Return an AbstractChains object from appliying pointwise_logdensities to Abstractchains? #688 for the motivation -- although OrderedDict output is still supported (I couldn't in good conscience allow it to return a lossy MCMCChains.Chains without leaving this option available)
  • Removes a handful of setval! methods that were only used for the old implementation (along with corresponding tests)
  • Moves the pointwise_logdensities family, as well as logjoint, loglikelihood and logprior, to MCMCChainsExt where they rightfully belong.
  • Fixes some overly broad logjoint, ... methods in src/simple_varinfo.jl

Closes #1072

Closes #688

Note, while working on this I discovered more problems.

The entirety of src/model_utils.jl is really meant for MCMCChains and should also be banished to the extension (or, in my opinion, removed; but then again I think that MCMCChains should just be removed, so...). The functions there are problematic in the same way that pointwise_... were (#1072) but at least they're only for internal use, so there is no reason for them to be overloaded by other types, so unlikely to cause problems in the future.

There are also issues with the current implementation of logjoint etc. on MCMCChains.Chains, they will only work if the set of varnames is static (i.e. no varying-size / varying-names).

Personally I think these remaining issues are comparatively unimportant and can be dealt with another time (or, indeed, never dealt with).

@penelopeysm penelopeysm changed the base branch from main to breaking October 15, 2025 18:28
Comment on lines -81 to +53
# T is the element type of the vectors that are the values of `acc.logps`. Usually
# it's LogProbType.
T = eltype(last(fieldtypes(eltype(acc.logps))))
# Note that in only accumulating LogPrior, we effectively ignore logjac
# (since we want to return log densities that don't depend on the
# linking status of the VarInfo).
subacc = accumulate_assume!!(LogPriorAccumulator{T}(), val, logjac, vn, right)
push!(acc, vn, subacc.logp)
acc.logps[vn] = logpdf(right, val)
Copy link
Member Author

Choose a reason for hiding this comment

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

I don't know if there was some point in going the circuitous route. Just calling logpdf seems much easier

Copy link
Member

Choose a reason for hiding this comment

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

I suspect this may have been leftover from an earlier iteration of the code, where the whichlogprob thing was a subaccumulator rather than a Symbol.

Comment on lines -42 to -44
# We'll just test one, since `pointwise_logdensities(::Model, ::AbstractVarInfo)` is tested extensively,
# and this is what is used to implement `pointwise_logdensities(::Model, ::Chains)`. This test suite is just
# to ensure that we don't accidentally break the version on `Chains`.
Copy link
Member Author

Choose a reason for hiding this comment

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

this comment is no longer appropriate since the varinfo method is not used to implement the chains method

@test typed_vi[vn_y] == 2.0
end

@testset "setval!" begin
Copy link
Member Author

Choose a reason for hiding this comment

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

these tests are no longer relevant since the corresponding methods are removed

Copy link

codecov bot commented Oct 15, 2025

Codecov Report

❌ Patch coverage is 95.91837% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.98%. Comparing base (9bd8f16) to head (7688065).
⚠️ Report is 1 commits behind head on breaking.

Files with missing lines Patch % Lines
ext/DynamicPPLMCMCChainsExt.jl 94.87% 2 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##           breaking    #1076      +/-   ##
============================================
- Coverage     82.40%   80.98%   -1.43%     
============================================
  Files            42       42              
  Lines          3791     3765      -26     
============================================
- Hits           3124     3049      -75     
- Misses          667      716      +49     

☔ 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
Contributor

DynamicPPL.jl documentation for PR #1076 is available at:
https://TuringLang.github.io/DynamicPPL.jl/previews/PR1076/

@penelopeysm penelopeysm marked this pull request as draft October 16, 2025 13:11
@penelopeysm penelopeysm marked this pull request as ready for review October 16, 2025 15:16
@penelopeysm penelopeysm requested a review from mhauru October 16, 2025 15:16
julia> # construct a chain of samples using MCMCChains
chain = Chains(rand(10, 2, 3), [:s, :m]);
julia> loglikelihood(demo_model([1., 2.]), chain);
Copy link
Member

Choose a reason for hiding this comment

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

Is it intentional that this doctest doesn't check the output at all?

Copy link
Member Author

Choose a reason for hiding this comment

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

Frankly, I'm not sure. I just copy-pasted it. Very happy to change it now.

Copy link
Member Author

Choose a reason for hiding this comment

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

Added the output! Also changed the rand() to some fixed values to avoid making it too fragile.

Comment on lines -81 to +53
# T is the element type of the vectors that are the values of `acc.logps`. Usually
# it's LogProbType.
T = eltype(last(fieldtypes(eltype(acc.logps))))
# Note that in only accumulating LogPrior, we effectively ignore logjac
# (since we want to return log densities that don't depend on the
# linking status of the VarInfo).
subacc = accumulate_assume!!(LogPriorAccumulator{T}(), val, logjac, vn, right)
push!(acc, vn, subacc.logp)
acc.logps[vn] = logpdf(right, val)
Copy link
Member

Choose a reason for hiding this comment

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

I suspect this may have been leftover from an earlier iteration of the code, where the whichlogprob thing was a subaccumulator rather than a Symbol.

@test !any(Base.Fix1(subsumes, @varname(x)), keys(logpriors_pointwise))
@test !any(vn in keys(loglikelihoods_pointwise) for vn in vns)
@test all(Base.Fix1(subsumes, @varname(x)), keys(loglikelihoods_pointwise))
@test all(Symbol(vn) in keys(logjoints_pointwise) for vn in vns)
Copy link
Member

Choose a reason for hiding this comment

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

I see the point of moving to a Chains return type, but this does feel like a regression. I can accept that, just mourning it out loud.

Copy link
Member Author

Choose a reason for hiding this comment

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

I totally agree 😄. I was mulling keeping the default as Dict, and make Chains output opt-in. What do you think?

Copy link
Member Author

Choose a reason for hiding this comment

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

(It's also less breaking.)

Copy link
Member

Choose a reason for hiding this comment

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

I do think long-term Chains feels like the right thing. We could choose to wait until MCMCChains has been improved, so that this would no longer be a regression. I'm quite ambivalent though.

Copy link
Member Author

@penelopeysm penelopeysm Oct 17, 2025

Choose a reason for hiding this comment

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

If it makes a difference (not that I think it should, really), I already implemented pointwise_... for FlexiChains and they return a FlexiChain: https://github.com/penelopeysm/FlexiChains.jl/blob/66b973e0fb346f3ef6cb51a6caa70324ef9d8f70/ext/FlexiChainsDynamicPPLExt.jl#L237-L254

@penelopeysm penelopeysm requested a review from mhauru October 17, 2025 11:10
Copy link
Member

@mhauru mhauru left a comment

Choose a reason for hiding this comment

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

I'm happy to merge. Happy either way on which one is the default, so change it if you want to.

@penelopeysm
Copy link
Member Author

Thanks! OK, Chains it is then

@penelopeysm penelopeysm merged commit e4c5bbd into breaking Oct 17, 2025
17 of 19 checks passed
@penelopeysm penelopeysm deleted the py/redo-pointwise branch October 17, 2025 16:45
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.

chains methods claim to be generic but only work on MCMCChains

2 participants