Skip to content

Conversation

ElOceanografo
Copy link
Contributor

Opening a new version of #2421, as discussed in #2662. Adds an extension for MarginalLogDensities.jl, along with a new exported marginalize function.

@coveralls
Copy link

coveralls commented Aug 25, 2025

Pull Request Test Coverage Report for Build 17257342637

Warning: This coverage report may be inaccurate.

This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.

Details

  • 0 of 13 (0.0%) changed or added relevant lines in 2 files are covered.
  • 381 unchanged lines in 12 files lost coverage.
  • Overall coverage decreased (-25.1%) to 58.426%

Changes Missing Coverage Covered Lines Changed/Added Lines %
src/extensions.jl 0 2 0.0%
ext/TuringMarginalLogDensitiesExt.jl 0 11 0.0%
Files with Coverage Reduction New Missed Lines %
src/mcmc/emcee.jl 2 90.0%
src/mcmc/external_sampler.jl 2 84.62%
src/mcmc/particle_mcmc.jl 8 85.08%
src/mcmc/hmc.jl 13 83.33%
src/stdlib/RandomMeasures.jl 22 0.0%
ext/TuringDynamicHMCExt.jl 25 0.0%
src/mcmc/mh.jl 35 58.33%
src/mcmc/sghmc.jl 41 25.45%
src/variational/VariationalInference.jl 44 0.0%
src/stdlib/distributions.jl 50 0.0%
Totals Coverage Status
Change from base Build 17044784653: -25.1%
Covered Lines: 839
Relevant Lines: 1436

💛 - Coveralls

Copy link

codecov bot commented Aug 25, 2025

Codecov Report

❌ Patch coverage is 0% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 58.22%. Comparing base (5a3f7aa) to head (edb0418).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
ext/TuringMarginalLogDensitiesExt.jl 0.00% 11 Missing ⚠️
src/extensions.jl 0.00% 2 Missing ⚠️

❗ There is a different number of reports uploaded between BASE (5a3f7aa) and HEAD (edb0418). Click for more details.

HEAD has 6 uploads less than BASE
Flag BASE (5a3f7aa) HEAD (edb0418)
25 19
Additional details and impacted files
@@             Coverage Diff             @@
##             main    #2664       +/-   ##
===========================================
- Coverage   85.70%   58.22%   -27.49%     
===========================================
  Files          22       24        +2     
  Lines        1434     1441        +7     
===========================================
- Hits         1229      839      -390     
- Misses        205      602      +397     

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

@penelopeysm penelopeysm left a comment

Choose a reason for hiding this comment

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

Thanks for this! Just some thoughts (no actual code).

Comment on lines 31 to 36
f = Turing.Optimisation.OptimLogDensity(
model,
Turing.DynamicPPL.getlogjoint,
# Turing.DynamicPPL.typed_varinfo(model)
varinfo_linked
)
Copy link
Member

Choose a reason for hiding this comment

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

Just making a note here that I am pretty sure that there's a double negative sign somewhere here with OptimLogDensity and the FlipSign thing, so I think we will be able to simplify this. (Pre-DynamicPPL 0.37, it used to be that OptimLogDensity was the only way to get the log-joint without the Jacobian term, so I'm guessing that's why it got used here, but now we can do that more easily with getlogjoint.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it's still needed, getlogjoint appears to return a negative log-density:

@model function demo()
       x ~ Normal()
end
model = demo()
f = Turing.Optimisation.OptimLogDensity(
        model,
        DynamicPPL.getlogjoint,
        DynamicPPL.typed_varinfo(model)
)
f([0]) # 0.9189385332046728
logpdf(Normal(), 0) #-0.9189385332046728

Copy link
Member

Choose a reason for hiding this comment

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

Ah, but that's the fault of OptimLogDensity not getlogjoint :)

Copy link
Member

Choose a reason for hiding this comment

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

Not asking you to fix it btw- happy to do it when I'm back to writing code!

Comment on lines 1 to 3
function marginalize(model, varnames, method)
error("This function is available after importing MarginalLogDensities.")
end
Copy link
Member

Choose a reason for hiding this comment

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

I looked through MLD's and Turing's deps, and the only new dep would be HCubature which is a pretty small dep. So I might be in favour to just making this part of the source code itself instead of an extension. (I think Julia extensions are a really good thing in general but there are a few downsides to them, like having to do this kind of 'define in main package and extend in extension' stuff.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, this one's up to you guys. I don't mind either way.

Comment on lines 40 to 44
mdl = MarginalLogDensities.MarginalLogDensity(
Drop2ndArgAndFlipSign(f), varinfo_linked[:], varindices, (), method
)
return mdl
end
Copy link
Member

Choose a reason for hiding this comment

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

From reading the MLD readme, I gather that you can do a couple of things with this:

  1. Evaluate the marginal log density by calling it
  2. Perform optimisation to get point estimates

Would it also be useful to be able to perform MCMC sampling with this? In principle it's not too difficult: a function that takes a vector of parameters, and returns a float, is pretty much what NUTS needs.

To do it properly will probably take a bit of time: I think we would have to either change the interface of DynamicPPL.LogDensityFunction or (perhaps easier) do a wrapper around it that keeps track of which variables are marginalised out. So it wouldn't have to be part of this PR. But if this is worth doing then I could have a think about how to do it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This should already work in theory, since MLD objects implement the LogDensityProblems interface (here). Would be good to add a test for it though.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Never mind, I thought it was "just working" but it isn't. Shouldn't be too hard to with some kind of simple wrapper though.

Copy link
Member

Choose a reason for hiding this comment

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

Yuppp, the samplers right now only work with DynamicPPL.Model. We should broaden those types and make an interface but it's quite a large undertaking.

Do you know if AD would be able to differentiate the marginal log-density?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not yet, it's the last major feature I need to add to MLD. It's a bit tricky since you need to differentiate through the Hessian of an optimization result, but it should be possible.

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.

3 participants