From 06752c41a97cd0dc37bb8700ab7a2d06f50f4f76 Mon Sep 17 00:00:00 2001 From: Penelope Yong Date: Fri, 24 Oct 2025 14:22:41 +0100 Subject: [PATCH 01/10] Decouple external sampler interface from Turing --- HISTORY.md | 16 ++++ Project.toml | 2 +- src/mcmc/external_sampler.jl | 135 +++++++++++++++++----------------- src/mcmc/gibbs.jl | 8 +- test/mcmc/external_sampler.jl | 14 ++-- 5 files changed, 91 insertions(+), 84 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index dc66f1f496..986d497c3a 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,21 @@ # 0.42.0 +## External sampler interface + +The interface for defining an external sampler has been reworked. +In general, implementations of external samplers should now no longer need to depend on Turing. +This is because the interface functions required have been shifted upstream to AbstractMCMC.jl. + +In particular, you now only need to define the following functions: + + - AbstractMCMC.step(rng::Random.AbstractRNG, model::AbstractMCMC.LogDensityModel, ::MySampler; kwargs...) (and also a method with `state`, and the corresponding `step_warmup` methods if needed) + - AbstractMCMC.getparams(::MySamplerState) -> Vector{<:Real} + - AbstractMCMC.getstats(::MySamplerState) -> NamedTuple + - AbstractMCMC.requires_unconstrained_space(::MySampler) -> Bool (default `true`) + +This means that you only need to depend on AbstractMCMC.jl. +As long as the above functions are defined correctly, Turing will be able to use your external sampler. + # 0.41.0 ## DynamicPPL 0.38 diff --git a/Project.toml b/Project.toml index 6db0028523..efb72e20d3 100644 --- a/Project.toml +++ b/Project.toml @@ -49,7 +49,7 @@ TuringOptimExt = ["Optim", "AbstractPPL"] [compat] ADTypes = "1.9" -AbstractMCMC = "5.5" +AbstractMCMC = "5.9" AbstractPPL = "0.11, 0.12, 0.13" Accessors = "0.1" AdvancedHMC = "0.3.0, 0.4.0, 0.5.2, 0.6, 0.7, 0.8" diff --git a/src/mcmc/external_sampler.jl b/src/mcmc/external_sampler.jl index f8673f6eef..43c97b3ec8 100644 --- a/src/mcmc/external_sampler.jl +++ b/src/mcmc/external_sampler.jl @@ -1,5 +1,5 @@ """ - ExternalSampler{S<:AbstractSampler,AD<:ADTypes.AbstractADType,Unconstrained} + ExternalSampler{Unconstrained,S<:AbstractSampler,AD<:ADTypes.AbstractADType} Represents a sampler that does not have a custom implementation of `AbstractMCMC.step(rng, ::DynamicPPL.Model, spl)`. @@ -14,45 +14,59 @@ $(TYPEDFIELDS) If you implement a new `MySampler <: AbstractSampler` and want it to work with Turing.jl models, there are two options: -1. Directly implement the `AbstractMCMC.step` methods for `DynamicPPL.Model`. This is the - most powerful option and is what Turing.jl's in-house samplers do. Implementing this - means that you can directly call `sample(model, MySampler(), N)`. +1. Directly implement the `AbstractMCMC.step` methods for `DynamicPPL.Model`. That is to + say, implement `AbstractMCMC.step(rng::Random.AbstractRNG, model::DynamicPPL.Model, + sampler::MySampler; kwargs...)` and related methods. This is the most powerful option and + is what Turing.jl's in-house samplers do. Implementing this means that you can directly + call `sample(model, MySampler(), N)`. -2. Implement a generic `AbstractMCMC.step` method for `AbstractMCMC.LogDensityModel`. This - struct wraps an object that obeys the LogDensityProblems.jl interface, so your `step` +2. Implement a generic `AbstractMCMC.step` method for `AbstractMCMC.LogDensityModel` (the + same signature as above except that `model::AbstractMCMC.LogDensityModel`). This struct + wraps an object that obeys the LogDensityProblems.jl interface, so your `step` implementation does not need to know anything about Turing.jl or DynamicPPL.jl. To use this with Turing.jl, you will need to wrap your sampler: `sample(model, externalsampler(MySampler()), N)`. This section describes the latter. -`MySampler` must implement the following methods: +`MySampler` **must** implement the following methods: - `AbstractMCMC.step` (the main function for taking a step in MCMC sampling; this is - documented in AbstractMCMC.jl) -- `Turing.Inference.getparams(::DynamicPPL.Model, external_transition)`: How to extract the - parameters from the transition returned by your sampler (i.e., the first return value of - `step`). There is a default implementation for this method, which is to return - `external_transition.θ`. - -!!! note - In a future breaking release of Turing, this is likely to change to - `AbstractMCMC.getparams(::DynamicPPL.Model, external_state)`, with no default method. - `Turing.Inference.getparams` is technically an internal method, so the aim here is to - unify the interface for samplers at a higher level. + documented in AbstractMCMC.jl). This function must return a tuple of two elements, a + 'transition' and a 'state'. + +- `AbstractMCMC.getparams(external_state)`: How to extract the parameters from the **state** + returned by your sampler (i.e., the **second** return value of `step`). For your sampler + to work with Turing.jl, this function should return a Vector of parameter values. Note that + this function does not need to perform any linking or unlinking; Turing.jl will take care of + this for you. You should return the parameters *exactly* as your sampler sees them. + +- `AbstractMCMC.getstats(external_state)`: Extract sampler statistics corresponding to this + iteration from the **state** returned by your sampler (i.e., the **second** return value + of `step`). For your sampler to work with Turing.jl, this function should return a + `NamedTuple`. If there are no statistics to return, return `NamedTuple()`. + + Note that `getstats` should not include log-probabilities as these will be recalculated by + Turing automatically for you. + +Notice that both of these functions take the **state** as input, not the **transition**. In +other words, the transition is completely useless for the external sampler interface. This is +in line with long-term plans for removing transitions from AbstractMCMC.jl and only using +states. There are a few more optional functions which you can implement to improve the integration with Turing.jl: -- `Turing.Inference.isgibbscomponent(::MySampler)`: If you want your sampler to function as - a component in Turing's Gibbs sampler, you should make this evaluate to `true`. - -- `Turing.Inference.requires_unconstrained_space(::MySampler)`: If your sampler requires +- `AbstractMCMC.requires_unconstrained_space(::MySampler)`: If your sampler requires unconstrained space, you should return `true`. This tells Turing to perform linking on the VarInfo before evaluation, and ensures that the parameter values passed to your sampler will always be in unconstrained (Euclidean) space. + +- `Turing.Inference.isgibbscomponent(::MySampler)`: If you want to disallow your sampler + from a component in Turing's Gibbs sampler, you should make this evaluate to `false`. Note + that the default is `true`, so you should only need to implement this in special cases. """ -struct ExternalSampler{S<:AbstractSampler,AD<:ADTypes.AbstractADType,Unconstrained} <: +struct ExternalSampler{Unconstrained,S<:AbstractSampler,AD<:ADTypes.AbstractADType} <: AbstractSampler "the sampler to wrap" sampler::S @@ -67,33 +81,20 @@ struct ExternalSampler{S<:AbstractSampler,AD<:ADTypes.AbstractADType,Unconstrain # Arguments - `sampler::AbstractSampler`: The sampler to wrap. - `adtype::ADTypes.AbstractADType`: The automatic differentiation (AD) backend to use. - - `unconstrained::Val=Val{true}()`: Value type containing a boolean indicating whether the sampler requires unconstrained space. + - `unconstrained::Val`: Value type containing a boolean indicating whether the sampler requires unconstrained space. """ function ExternalSampler( - sampler::AbstractSampler, - adtype::ADTypes.AbstractADType, - (::Val{unconstrained})=Val(true), + sampler::AbstractSampler, adtype::ADTypes.AbstractADType, ::Val{unconstrained} ) where {unconstrained} if !(unconstrained isa Bool) throw( ArgumentError("Expected Val{true} or Val{false}, got Val{$unconstrained}") ) end - return new{typeof(sampler),typeof(adtype),unconstrained}(sampler, adtype) + return new{unconstrained,typeof(sampler),typeof(adtype)}(sampler, adtype) end end -""" - requires_unconstrained_space(sampler::ExternalSampler) - -Return `true` if the sampler requires unconstrained space, and `false` otherwise. -""" -function requires_unconstrained_space( - ::ExternalSampler{<:Any,<:Any,Unconstrained} -) where {Unconstrained} - return Unconstrained -end - """ externalsampler(sampler::AbstractSampler; adtype=AutoForwardDiff(), unconstrained=true) @@ -106,10 +107,10 @@ Wrap a sampler so it can be used as an inference algorithm. - `adtype::ADTypes.AbstractADType=ADTypes.AutoForwardDiff()`: The automatic differentiation (AD) backend to use. - `unconstrained::Bool=true`: Whether the sampler requires unconstrained space. """ -function externalsampler( - sampler::AbstractSampler; adtype=Turing.DEFAULT_ADTYPE, unconstrained::Bool=true -) - return ExternalSampler(sampler, adtype, Val(unconstrained)) +function externalsampler(sampler::AbstractSampler; adtype=Turing.DEFAULT_ADTYPE) + return ExternalSampler( + sampler, adtype, Val(AbstractMCMC.requires_unconstrained_space(sampler)) + ) end # TODO(penelopeysm): Can't we clean this up somehow? @@ -128,30 +129,22 @@ end get_varinfo(state::TuringState) = state.varinfo get_varinfo(state::AbstractVarInfo) = state -getparams(::DynamicPPL.Model, transition::AdvancedHMC.Transition) = transition.z.θ -function getparams(model::DynamicPPL.Model, state::AdvancedHMC.HMCState) - return getparams(model, state.transition) -end -getstats(transition::AdvancedHMC.Transition) = transition.stat - -getparams(::DynamicPPL.Model, transition::AdvancedMH.Transition) = transition.params - # TODO: Do we also support `resume`, etc? function AbstractMCMC.step( rng::Random.AbstractRNG, model::DynamicPPL.Model, - sampler_wrapper::ExternalSampler; + sampler_wrapper::ExternalSampler{unconstrained}; initial_state=nothing, initial_params, # passed through from sample kwargs..., -) +) where {unconstrained} sampler = sampler_wrapper.sampler # Initialise varinfo with initial params and link the varinfo if needed. varinfo = DynamicPPL.VarInfo(model) _, varinfo = DynamicPPL.init!!(rng, model, varinfo, initial_params) - if requires_unconstrained_space(sampler_wrapper) + if unconstrained varinfo = DynamicPPL.link(varinfo, model) end @@ -166,16 +159,17 @@ function AbstractMCMC.step( ) # Then just call `AbstractMCMC.step` with the right arguments. - if initial_state === nothing - transition_inner, state_inner = AbstractMCMC.step( + _, state_inner = if initial_state === nothing + AbstractMCMC.step( rng, AbstractMCMC.LogDensityModel(f), sampler; initial_params=initial_params_vector, kwargs..., ) + else - transition_inner, state_inner = AbstractMCMC.step( + AbstractMCMC.step( rng, AbstractMCMC.LogDensityModel(f), sampler, @@ -185,13 +179,12 @@ function AbstractMCMC.step( ) end - # NOTE: This is Turing.Inference.getparams, not AbstractMCMC.getparams (!!!!!) - # The latter uses the state rather than the transition. - # TODO(penelopeysm): Make this use AbstractMCMC.getparams instead - new_parameters = Turing.Inference.getparams(f.model, transition_inner) + new_parameters = AbstractMCMC.getparams(f.model, state_inner) new_vi = DynamicPPL.unflatten(f.varinfo, new_parameters) + new_stats = AbstractMCMC.getstats(state_inner) return ( - Transition(f.model, new_vi, transition_inner), TuringState(state_inner, new_vi, f) + Turing.Inference.Transition(f.model, new_vi, new_stats), + TuringState(state_inner, new_vi, f), ) end @@ -206,16 +199,22 @@ function AbstractMCMC.step( f = state.ldf # Then just call `AdvancedMCMC.step` with the right arguments. - transition_inner, state_inner = AbstractMCMC.step( + _, state_inner = AbstractMCMC.step( rng, AbstractMCMC.LogDensityModel(f), sampler, state.state; kwargs... ) - # NOTE: This is Turing.Inference.getparams, not AbstractMCMC.getparams (!!!!!) - # The latter uses the state rather than the transition. - # TODO(penelopeysm): Make this use AbstractMCMC.getparams instead - new_parameters = Turing.Inference.getparams(f.model, transition_inner) + new_parameters = AbstractMCMC.getparams(f.model, state_inner) new_vi = DynamicPPL.unflatten(f.varinfo, new_parameters) + new_stats = AbstractMCMC.getstats(state_inner) return ( - Transition(f.model, new_vi, transition_inner), TuringState(state_inner, new_vi, f) + Turing.Inference.Transition(f.model, new_vi, new_stats), + TuringState(state_inner, new_vi, f), ) end + +# Implementation of interface for AdvancedMH and AdvancedHMC. TODO: These should be +# upstreamed to the respective packages, I'm just not doing it here to avoid having to run +# CI against three separate PR branches. +AbstractMCMC.getstats(state::AdvancedHMC.HMCState) = state.transition.stat +# Note that for AdvancedMH, transition and state are equivalent (and both named Transition) +AbstractMCMC.getstats(state::AdvancedMH.Transition) = (accepted=state.accepted,) diff --git a/src/mcmc/gibbs.jl b/src/mcmc/gibbs.jl index 7d15829a3c..a16c973953 100644 --- a/src/mcmc/gibbs.jl +++ b/src/mcmc/gibbs.jl @@ -3,9 +3,9 @@ Return a boolean indicating whether `spl` is a valid component for a Gibbs sampler. -Defaults to `false` if no method has been defined for a particular algorithm type. +Defaults to `true` if no method has been defined for a particular sampler. """ -isgibbscomponent(::AbstractSampler) = false +isgibbscomponent(::AbstractSampler) = true isgibbscomponent(::ESS) = true isgibbscomponent(::HMC) = true @@ -15,11 +15,7 @@ isgibbscomponent(::MH) = true isgibbscomponent(::PG) = true isgibbscomponent(spl::RepeatSampler) = isgibbscomponent(spl.sampler) - isgibbscomponent(spl::ExternalSampler) = isgibbscomponent(spl.sampler) -isgibbscomponent(::AdvancedHMC.AbstractHMCSampler) = true -isgibbscomponent(::AdvancedMH.MetropolisHastings) = true -isgibbscomponent(spl) = false function can_be_wrapped(ctx::DynamicPPL.AbstractContext) return DynamicPPL.NodeTrait(ctx) isa DynamicPPL.IsLeaf diff --git a/test/mcmc/external_sampler.jl b/test/mcmc/external_sampler.jl index 56c03c87a8..36f53462ec 100644 --- a/test/mcmc/external_sampler.jl +++ b/test/mcmc/external_sampler.jl @@ -20,16 +20,11 @@ using Turing.Inference: AdvancedHMC # Turing declares an interface for external samplers (see docstring for # ExternalSampler). We should check that implementing this interface # and only this interface allows us to use the sampler in Turing. - struct MyTransition{V<:AbstractVector} - params::V - end - # Samplers need to implement `Turing.Inference.getparams`. - Turing.Inference.getparams(::DynamicPPL.Model, t::MyTransition) = t.params - # State doesn't matter (but we need to carry the params through to the next - # iteration). struct MyState{V<:AbstractVector} params::V end + AbstractMCMC.getparams(s::MyState) = s.params + AbstractMCMC.getstats(s::MyState) = (param_length=length(s.params),) # externalsamplers must accept LogDensityModel inside their step function. # By default Turing gives the externalsampler a LDF constructed with @@ -58,7 +53,7 @@ using Turing.Inference: AdvancedHMC lp, grad = LogDensityProblems.logdensity_and_gradient(ldf, initial_params) @test lp isa Real @test grad isa AbstractVector{<:Real} - return MyTransition(initial_params), MyState(initial_params) + return nothing, MyState(initial_params) end function AbstractMCMC.step( rng::Random.AbstractRNG, @@ -75,7 +70,7 @@ using Turing.Inference: AdvancedHMC lp, grad = LogDensityProblems.logdensity_and_gradient(ldf, params) @test lp isa Real @test grad isa AbstractVector{<:Real} - return MyTransition(params), MyState(params) + return nothing, MyState(params) end @model function test_external_sampler() @@ -96,6 +91,7 @@ using Turing.Inference: AdvancedHMC @test all(chn[:lp] .== expected_logpdf) @test all(chn[:logprior] .== expected_logpdf) @test all(chn[:loglikelihood] .== 0.0) + @test all(chn[:param_length] .== 2) end function initialize_nuts(model::DynamicPPL.Model) From 8fec487908b7d2ce36d43b1c9cd05042e8c432aa Mon Sep 17 00:00:00 2001 From: Penelope Yong Date: Fri, 24 Oct 2025 14:30:57 +0100 Subject: [PATCH 02/10] Delete a todo note --- src/mcmc/external_sampler.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mcmc/external_sampler.jl b/src/mcmc/external_sampler.jl index 43c97b3ec8..77a07460de 100644 --- a/src/mcmc/external_sampler.jl +++ b/src/mcmc/external_sampler.jl @@ -129,7 +129,6 @@ end get_varinfo(state::TuringState) = state.varinfo get_varinfo(state::AbstractVarInfo) = state -# TODO: Do we also support `resume`, etc? function AbstractMCMC.step( rng::Random.AbstractRNG, model::DynamicPPL.Model, From 46354fb040c689228cb069969db772601d0ad97f Mon Sep 17 00:00:00 2001 From: Penelope Yong Date: Fri, 24 Oct 2025 14:33:16 +0100 Subject: [PATCH 03/10] Changelog --- HISTORY.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index 986d497c3a..e716b90327 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -16,6 +16,8 @@ In particular, you now only need to define the following functions: This means that you only need to depend on AbstractMCMC.jl. As long as the above functions are defined correctly, Turing will be able to use your external sampler. +The `Turing.Inference.isgibbscomponent(::MySampler)` interface function still exists, but in this version the default has been changed to `true`, so you should not need to overload this. + # 0.41.0 ## DynamicPPL 0.38 From c7ffadaab2919c3c9500b53002de5575118d83c8 Mon Sep 17 00:00:00 2001 From: Penelope Yong Date: Fri, 24 Oct 2025 14:39:20 +0100 Subject: [PATCH 04/10] Temp point to AbstractMCMC feature branch --- Project.toml | 3 +++ test/Project.toml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/Project.toml b/Project.toml index efb72e20d3..f450cfa49c 100644 --- a/Project.toml +++ b/Project.toml @@ -90,3 +90,6 @@ julia = "1.10.8" [extras] DynamicHMC = "bbc10e6e-7c05-544b-b16e-64fede858acb" Optim = "429524aa-4258-5aef-a3af-852621145aeb" + +[sources] +AbstractMCMC = {url = "https://github.com/TuringLang/AbstractMCMC.jl", rev = "py/getstats"} diff --git a/test/Project.toml b/test/Project.toml index 435f8cc5f2..b2c936f863 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -76,3 +76,6 @@ StatsBase = "0.33, 0.34" StatsFuns = "0.9.5, 1" TimerOutputs = "0.5" julia = "1.10" + +[sources] +AbstractMCMC = {url = "https://github.com/TuringLang/AbstractMCMC.jl", rev = "py/getstats"} From eacffdbfbbd8079ff71216f12c7c38ed881d0abc Mon Sep 17 00:00:00 2001 From: Penelope Yong Date: Fri, 24 Oct 2025 16:39:22 +0100 Subject: [PATCH 05/10] Fix tests --- src/mcmc/gibbs.jl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/mcmc/gibbs.jl b/src/mcmc/gibbs.jl index a16c973953..1ff50a646d 100644 --- a/src/mcmc/gibbs.jl +++ b/src/mcmc/gibbs.jl @@ -7,16 +7,16 @@ Defaults to `true` if no method has been defined for a particular sampler. """ isgibbscomponent(::AbstractSampler) = true -isgibbscomponent(::ESS) = true -isgibbscomponent(::HMC) = true -isgibbscomponent(::HMCDA) = true -isgibbscomponent(::NUTS) = true -isgibbscomponent(::MH) = true -isgibbscomponent(::PG) = true - isgibbscomponent(spl::RepeatSampler) = isgibbscomponent(spl.sampler) isgibbscomponent(spl::ExternalSampler) = isgibbscomponent(spl.sampler) +isgibbscomponent(::IS) = false +isgibbscomponent(::Prior) = false +isgibbscomponent(::Emcee) = false +isgibbscomponent(::SGLD) = false +isgibbscomponent(::SGHMC) = false +isgibbscomponent(::SMC) = false + function can_be_wrapped(ctx::DynamicPPL.AbstractContext) return DynamicPPL.NodeTrait(ctx) isa DynamicPPL.IsLeaf end From 9b30bea5db546d5cc65a3c194f9dcf58b4576b04 Mon Sep 17 00:00:00 2001 From: Penelope Yong Date: Fri, 24 Oct 2025 16:41:32 +0100 Subject: [PATCH 06/10] Don't remove the keyword argument --- src/mcmc/external_sampler.jl | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/mcmc/external_sampler.jl b/src/mcmc/external_sampler.jl index 77a07460de..3fa8855659 100644 --- a/src/mcmc/external_sampler.jl +++ b/src/mcmc/external_sampler.jl @@ -96,7 +96,11 @@ struct ExternalSampler{Unconstrained,S<:AbstractSampler,AD<:ADTypes.AbstractADTy end """ - externalsampler(sampler::AbstractSampler; adtype=AutoForwardDiff(), unconstrained=true) + externalsampler( + sampler::AbstractSampler; + adtype=AutoForwardDiff(), + unconstrained=AbstractMCMC.requires_unconstrained_space(sampler), + ) Wrap a sampler so it can be used as an inference algorithm. @@ -104,13 +108,17 @@ Wrap a sampler so it can be used as an inference algorithm. - `sampler::AbstractSampler`: The sampler to wrap. # Keyword Arguments -- `adtype::ADTypes.AbstractADType=ADTypes.AutoForwardDiff()`: The automatic differentiation (AD) backend to use. -- `unconstrained::Bool=true`: Whether the sampler requires unconstrained space. +- `adtype::ADTypes.AbstractADType=ADTypes.AutoForwardDiff()`: The automatic differentiation + (AD) backend to use. +- `unconstrained::Bool=AbstractMCMC.requires_unconstrained_space(sampler)`: Whether the + sampler requires unconstrained space. """ -function externalsampler(sampler::AbstractSampler; adtype=Turing.DEFAULT_ADTYPE) - return ExternalSampler( - sampler, adtype, Val(AbstractMCMC.requires_unconstrained_space(sampler)) - ) +function externalsampler( + sampler::AbstractSampler; + adtype=Turing.DEFAULT_ADTYPE, + unconstrained::Bool=AbstractMCMC.requires_unconstrained_space(sampler), +) + return ExternalSampler(sampler, adtype, Val(unconstrained)) end # TODO(penelopeysm): Can't we clean this up somehow? From 0ebf0e8105f8eb6f0d12d27f72e988815f265c90 Mon Sep 17 00:00:00 2001 From: Penelope Yong Date: Sat, 25 Oct 2025 21:05:56 +0100 Subject: [PATCH 07/10] Fix import order --- src/mcmc/Inference.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mcmc/Inference.jl b/src/mcmc/Inference.jl index 7d25ecd7ee..695f9c3aa1 100644 --- a/src/mcmc/Inference.jl +++ b/src/mcmc/Inference.jl @@ -429,10 +429,10 @@ include("hmc.jl") include("mh.jl") include("is.jl") include("particle_mcmc.jl") -include("gibbs.jl") include("sghmc.jl") include("emcee.jl") include("prior.jl") +include("gibbs.jl") ################ # Typing tools # From c464b0c027c0455ccfdd64e14b22e4d0a61faf92 Mon Sep 17 00:00:00 2001 From: Penelope Yong Date: Mon, 3 Nov 2025 10:10:56 +0000 Subject: [PATCH 08/10] Upstream `getstats` definitions to AdvancedMH/AdvancedHMC --- Project.toml | 4 ++-- src/mcmc/external_sampler.jl | 7 ------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/Project.toml b/Project.toml index f450cfa49c..70bc55e03e 100644 --- a/Project.toml +++ b/Project.toml @@ -52,8 +52,8 @@ ADTypes = "1.9" AbstractMCMC = "5.9" AbstractPPL = "0.11, 0.12, 0.13" Accessors = "0.1" -AdvancedHMC = "0.3.0, 0.4.0, 0.5.2, 0.6, 0.7, 0.8" -AdvancedMH = "0.8" +AdvancedHMC = "0.8.3" +AdvancedMH = "0.8.9" AdvancedPS = "0.7" AdvancedVI = "0.4" BangBang = "0.4.2" diff --git a/src/mcmc/external_sampler.jl b/src/mcmc/external_sampler.jl index 3fa8855659..94e9e17061 100644 --- a/src/mcmc/external_sampler.jl +++ b/src/mcmc/external_sampler.jl @@ -218,10 +218,3 @@ function AbstractMCMC.step( TuringState(state_inner, new_vi, f), ) end - -# Implementation of interface for AdvancedMH and AdvancedHMC. TODO: These should be -# upstreamed to the respective packages, I'm just not doing it here to avoid having to run -# CI against three separate PR branches. -AbstractMCMC.getstats(state::AdvancedHMC.HMCState) = state.transition.stat -# Note that for AdvancedMH, transition and state are equivalent (and both named Transition) -AbstractMCMC.getstats(state::AdvancedMH.Transition) = (accepted=state.accepted,) From e99c154555402fdddecfd6833436ba575764afbd Mon Sep 17 00:00:00 2001 From: Penelope Yong Date: Mon, 3 Nov 2025 10:45:08 +0000 Subject: [PATCH 09/10] remove sources --- Project.toml | 3 --- test/Project.toml | 3 --- 2 files changed, 6 deletions(-) diff --git a/Project.toml b/Project.toml index 70bc55e03e..23a8af183d 100644 --- a/Project.toml +++ b/Project.toml @@ -90,6 +90,3 @@ julia = "1.10.8" [extras] DynamicHMC = "bbc10e6e-7c05-544b-b16e-64fede858acb" Optim = "429524aa-4258-5aef-a3af-852621145aeb" - -[sources] -AbstractMCMC = {url = "https://github.com/TuringLang/AbstractMCMC.jl", rev = "py/getstats"} diff --git a/test/Project.toml b/test/Project.toml index b2c936f863..435f8cc5f2 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -76,6 +76,3 @@ StatsBase = "0.33, 0.34" StatsFuns = "0.9.5, 1" TimerOutputs = "0.5" julia = "1.10" - -[sources] -AbstractMCMC = {url = "https://github.com/TuringLang/AbstractMCMC.jl", rev = "py/getstats"} From d8dcd11a7c00fbea7b7242845546cffe5333e75a Mon Sep 17 00:00:00 2001 From: Penelope Yong Date: Mon, 3 Nov 2025 10:48:25 +0000 Subject: [PATCH 10/10] Bump test deps (probably pointless, but eh) --- test/Project.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Project.toml b/test/Project.toml index 435f8cc5f2..f0292a71a3 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -40,9 +40,9 @@ TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f" [compat] ADTypes = "1" -AbstractMCMC = "5" +AbstractMCMC = "5.9" AbstractPPL = "0.11, 0.12, 0.13" -AdvancedMH = "0.6, 0.7, 0.8" +AdvancedMH = "0.8.9" AdvancedPS = "0.7" AdvancedVI = "0.4" Aqua = "0.8"