From 669e26af68f64358f90dae09597fe8d4ef6ebcd4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 26 Oct 2023 19:52:00 +0100 Subject: [PATCH 01/20] CompatHelper: bump compat for AbstractMCMC to 5, (keep existing compat) (#352) Co-authored-by: CompatHelper Julia --- Project.toml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Project.toml b/Project.toml index b7d2576b..029cb97d 100644 --- a/Project.toml +++ b/Project.toml @@ -19,8 +19,18 @@ Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" StatsFuns = "4c63d2b9-4356-54db-8cca-17b64c39e42c" +[weakdeps] +CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" +MCMCChains = "c7f686f2-ff18-58e9-bc7b-31028e88f75d" +OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" + +[extensions] +AdvancedHMCCUDAExt = "CUDA" +AdvancedHMCMCMCChainsExt = "MCMCChains" +AdvancedHMCOrdinaryDiffEqExt = "OrdinaryDiffEq" + [compat] -AbstractMCMC = "4.2" +AbstractMCMC = "4.2, 5" ArgCheck = "1, 2" CUDA = "3, 4" DocStringExtensions = "0.8, 0.9" @@ -37,17 +47,7 @@ StatsBase = "0.31, 0.32, 0.33, 0.34" StatsFuns = "0.8, 0.9, 1" julia = "1.6" -[extensions] -AdvancedHMCCUDAExt = "CUDA" -AdvancedHMCMCMCChainsExt = "MCMCChains" -AdvancedHMCOrdinaryDiffEqExt = "OrdinaryDiffEq" - [extras] CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" MCMCChains = "c7f686f2-ff18-58e9-bc7b-31028e88f75d" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" - -[weakdeps] -CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" -MCMCChains = "c7f686f2-ff18-58e9-bc7b-31028e88f75d" -OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" From 223978521339eec8e269014e487752996d68a735 Mon Sep 17 00:00:00 2001 From: Hong Ge <3279477+yebai@users.noreply.github.com> Date: Thu, 26 Oct 2023 21:11:33 +0100 Subject: [PATCH 02/20] Update Project.toml --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 029cb97d..1a0cb3ba 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "AdvancedHMC" uuid = "0bf59076-c3b1-5ca4-86bd-e02cd72cde3d" -version = "0.5.5" +version = "0.5.6" [deps] AbstractMCMC = "80f14c24-f653-4e6a-9b94-39d6b0f70001" From f108fe36c3112dd472f927731ff76d58c4756e47 Mon Sep 17 00:00:00 2001 From: Tor Erlend Fjelde Date: Fri, 27 Oct 2023 18:26:37 +0100 Subject: [PATCH 03/20] Deprecate `init_params` which is no longer in AbstractMCMC (#353) * deprecate init_params keyword in favour of initial_params * Update src/abstractmcmc.jl Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/abstractmcmc.jl | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/abstractmcmc.jl b/src/abstractmcmc.jl index 786b6caa..2cfba145 100644 --- a/src/abstractmcmc.jl +++ b/src/abstractmcmc.jl @@ -103,9 +103,15 @@ function AbstractMCMC.step( rng::AbstractRNG, model::LogDensityModel, spl::AbstractHMCSampler; - init_params = nothing, + initial_params = nothing, + init_params = initial_params, kwargs..., ) + if init_params !== initial_params + Base.depwarn("`init_params` is deprecated, use `initial_params` instead", :step) + initial_params = init_params + end + # Unpack model logdensity = model.logdensity @@ -117,8 +123,8 @@ function AbstractMCMC.step( # Define integration algorithm # Find good eps if not provided one - init_params = make_init_params(rng, spl, logdensity, init_params) - ϵ = make_step_size(rng, spl, hamiltonian, init_params) + initial_params = make_init_params(rng, spl, logdensity, initial_params) + ϵ = make_step_size(rng, spl, hamiltonian, initial_params) integrator = make_integrator(spl, ϵ) # Make kernel @@ -128,7 +134,7 @@ function AbstractMCMC.step( adaptor = make_adaptor(spl, metric, integrator) # Get an initial sample. - h, t = AdvancedHMC.sample_init(rng, hamiltonian, init_params) + h, t = AdvancedHMC.sample_init(rng, hamiltonian, initial_params) # Compute next transition and state. state = HMCState(0, t, metric, κ, adaptor) From 362a05368183e9d6032ead010fd194a3e4dffd0a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 29 Oct 2023 22:37:22 +0000 Subject: [PATCH 04/20] CompatHelper: add new compat entry for Statistics at version 1, (keep existing compat) (#354) Co-authored-by: CompatHelper Julia --- Project.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Project.toml b/Project.toml index 1a0cb3ba..a0551e76 100644 --- a/Project.toml +++ b/Project.toml @@ -43,6 +43,7 @@ ProgressMeter = "1" Requires = "0.5, 1" Setfield = "0.7, 0.8, 1" SimpleUnPack = "1.1" +Statistics = "1" StatsBase = "0.31, 0.32, 0.33, 0.34" StatsFuns = "0.8, 0.9, 1" julia = "1.6" From 5ac886ddb1f4cd5e8bd83843b7bfc4e998e08894 Mon Sep 17 00:00:00 2001 From: Tor Erlend Fjelde Date: Thu, 2 Nov 2023 19:34:44 +0000 Subject: [PATCH 05/20] Removed deprecation of init_params + bump minor version (#355) * removed deprecation of init_params and only allow the new initial_params * bump minor version since change is breaking * Fix some tests. (#356) * CompatHelper: add new compat entry for Statistics at version 1, (keep existing compat) (#354) Co-authored-by: CompatHelper Julia * Update constructors.jl * Update constructors.jl * Update test/constructors.jl Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update Project.toml * Update abstractmcmc.jl --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: CompatHelper Julia * Fix docs CI (#357) * Update make.jl * Update trajectory.jl * Update integrator.jl * Update metric.jl * Update constructors.jl * Update api.md * Update constructors.jl * Update Adaptation.jl * Update abstractmcmc.jl * Update Adaptation.jl * Update Adaptation.jl * Update api.md * Update constructors.jl * Update api.md * Update make.jl * Update docs/make.jl Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update docs/make.jl Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --------- Co-authored-by: Hong Ge <3279477+yebai@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: CompatHelper Julia --- Project.toml | 4 ++-- docs/make.jl | 6 +++++- docs/src/api.md | 11 ++++++++-- src/abstractmcmc.jl | 42 ++++++++++++++++-------------------- src/adaptation/Adaptation.jl | 6 ++++++ src/constructors.jl | 6 +++--- src/integrator.jl | 2 +- src/metric.jl | 5 +++++ src/trajectory.jl | 16 ++++++++++++++ test/constructors.jl | 22 +++++++++++-------- 10 files changed, 78 insertions(+), 42 deletions(-) diff --git a/Project.toml b/Project.toml index a0551e76..4fe85fe9 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "AdvancedHMC" uuid = "0bf59076-c3b1-5ca4-86bd-e02cd72cde3d" -version = "0.5.6" +version = "0.6.0" [deps] AbstractMCMC = "80f14c24-f653-4e6a-9b94-39d6b0f70001" @@ -43,7 +43,7 @@ ProgressMeter = "1" Requires = "0.5, 1" Setfield = "0.7, 0.8, 1" SimpleUnPack = "1.1" -Statistics = "1" +Statistics = "1.6" StatsBase = "0.31, 0.32, 0.33, 0.34" StatsFuns = "0.8, 0.9, 1" julia = "1.6" diff --git a/docs/make.jl b/docs/make.jl index 83c5475d..bdc801c0 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -5,7 +5,11 @@ using AdvancedHMC # cp(joinpath(@__DIR__, "../README.md"), joinpath(@__DIR__, "src/index.md")) -makedocs(sitename = "AdvancedHMC", format = Documenter.HTML(), modules = [AdvancedHMC]) +makedocs( + sitename = "AdvancedHMC", + format = Documenter.HTML(), + warnonly = [:cross_references], +) deploydocs( repo = "github.com/TuringLang/AdvancedHMC.jl.git", diff --git a/docs/src/api.md b/docs/src/api.md index 8754eb2f..80859f5c 100644 --- a/docs/src/api.md +++ b/docs/src/api.md @@ -5,7 +5,7 @@ Documentation for AdvancedHMC.jl ```@contents ``` -## Structs +## Types ```@docs ClassicNoUTurn HMCSampler @@ -18,4 +18,11 @@ HMCDA ```@docs sample -``` \ No newline at end of file +``` + +## More types + +```@autodocs; canonical=false +Modules = [AdvancedHMC, AdvancedHMC.Adaptation] +Order = [:type] +``` diff --git a/src/abstractmcmc.jl b/src/abstractmcmc.jl index 2cfba145..905deaf7 100644 --- a/src/abstractmcmc.jl +++ b/src/abstractmcmc.jl @@ -38,7 +38,7 @@ A convenient wrapper around `AbstractMCMC.sample` avoiding explicit construction function AbstractMCMC.sample( rng::Random.AbstractRNG, - model::LogDensityModel, + model::AbstractMCMC.LogDensityModel, sampler::AbstractHMCSampler, N::Integer; n_adapts::Int = min(div(N, 10), 1_000), @@ -67,7 +67,7 @@ end function AbstractMCMC.sample( rng::Random.AbstractRNG, - model::LogDensityModel, + model::AbstractMCMC.LogDensityModel, sampler::AbstractHMCSampler, parallel::AbstractMCMC.AbstractMCMCEnsemble, N::Integer, @@ -101,17 +101,11 @@ end function AbstractMCMC.step( rng::AbstractRNG, - model::LogDensityModel, + model::AbstractMCMC.LogDensityModel, spl::AbstractHMCSampler; initial_params = nothing, - init_params = initial_params, kwargs..., ) - if init_params !== initial_params - Base.depwarn("`init_params` is deprecated, use `initial_params` instead", :step) - initial_params = init_params - end - # Unpack model logdensity = model.logdensity @@ -123,7 +117,7 @@ function AbstractMCMC.step( # Define integration algorithm # Find good eps if not provided one - initial_params = make_init_params(rng, spl, logdensity, initial_params) + initial_params = make_initial_params(rng, spl, logdensity, initial_params) ϵ = make_step_size(rng, spl, hamiltonian, initial_params) integrator = make_integrator(spl, ϵ) @@ -144,7 +138,7 @@ end function AbstractMCMC.step( rng::AbstractRNG, - model::LogDensityModel, + model::AbstractMCMC.LogDensityModel, spl::AbstractHMCSampler, state::HMCState; kwargs..., @@ -257,18 +251,18 @@ end ############# ### Utils ### ############# -function make_init_params( +function make_initial_params( rng::AbstractRNG, spl::AbstractHMCSampler, logdensity, - init_params, + initial_params, ) T = sampler_eltype(spl) - if init_params == nothing + if initial_params == nothing d = LogDensityProblems.dimension(logdensity) - init_params = randn(rng, d) + initial_params = randn(rng, d) end - return T.(init_params) + return T.(initial_params) end ######### @@ -277,10 +271,10 @@ function make_step_size( rng::Random.AbstractRNG, spl::HMCSampler, hamiltonian::Hamiltonian, - init_params, + initial_params, ) T = typeof(spl.κ.τ.integrator.ϵ) - ϵ = make_step_size(rng, spl.κ.τ.integrator, T, hamiltonian, init_params) + ϵ = make_step_size(rng, spl.κ.τ.integrator, T, hamiltonian, initial_params) return ϵ end @@ -288,10 +282,10 @@ function make_step_size( rng::Random.AbstractRNG, spl::AbstractHMCSampler, hamiltonian::Hamiltonian, - init_params, + initial_params, ) T = sampler_eltype(spl) - return make_step_size(rng, spl.integrator, T, hamiltonian, init_params) + return make_step_size(rng, spl.integrator, T, hamiltonian, initial_params) end @@ -300,12 +294,12 @@ function make_step_size( integrator::AbstractIntegrator, T::Type, hamiltonian::Hamiltonian, - init_params, + initial_params, ) if integrator.ϵ > 0 ϵ = integrator.ϵ else - ϵ = find_good_stepsize(rng, hamiltonian, init_params) + ϵ = find_good_stepsize(rng, hamiltonian, initial_params) @info string("Found initial step size ", ϵ) end return T(ϵ) @@ -316,9 +310,9 @@ function make_step_size( integrator::Symbol, T::Type, hamiltonian::Hamiltonian, - init_params, + initial_params, ) - ϵ = find_good_stepsize(rng, hamiltonian, init_params) + ϵ = find_good_stepsize(rng, hamiltonian, initial_params) @info string("Found initial step size ", ϵ) return T(ϵ) end diff --git a/src/adaptation/Adaptation.jl b/src/adaptation/Adaptation.jl index 72c7a017..a7c7ff0e 100644 --- a/src/adaptation/Adaptation.jl +++ b/src/adaptation/Adaptation.jl @@ -6,7 +6,13 @@ using Statistics: Statistics using SimpleUnPack: @unpack, @pack! using ..AdvancedHMC: DEBUG, AbstractScalarOrVec +using DocStringExtensions +""" +$(TYPEDEF) + +Abstract type for HMC adaptors. +""" abstract type AbstractAdaptor end function getM⁻¹ end function getϵ end diff --git a/src/constructors.jl b/src/constructors.jl index 6ccf55c2..297e9bdd 100644 --- a/src/constructors.jl +++ b/src/constructors.jl @@ -8,7 +8,7 @@ in favour of determined types from the other arguments. """ determine_sampler_eltype(xs...) = float(_determine_sampler_eltype(xs...)) # NOTE: We want to defer conversion to `float` until the very "end" of the -# process, so as to allow `promote_type` to do it's job properly. +# process to allow `promote_type` to do its job properly. # For example, in the scenario `determine_sampler_eltype(::Int64, ::Float32)` # we want to return `Float32`, not `Float64`. The latter would occur # if we did `float(eltype(x))` instead of just `eltype(x)`. @@ -49,7 +49,7 @@ Note that all the fields have the prefix `initial_` to indicate that these will not necessarily correspond to the `kernel`, `metric`, and `adaptor` after sampling. -To access the updated fields use the resulting [`HMCState`](@ref). +To access the updated fields, use the resulting [`HMCState`](@ref). """ struct HMCSampler{K<:AbstractMCMCKernel,M<:AbstractMetric,A<:AbstractAdaptor} <: AbstractHMCSampler @@ -57,7 +57,7 @@ struct HMCSampler{K<:AbstractMCMCKernel,M<:AbstractMetric,A<:AbstractAdaptor} <: κ::K "Choice of initial metric [`AbstractMetric`](@ref). The metric type will be preserved during adaption." metric::M - "[`AbstractAdaptor`](@ref)." + "[`AdvancedHMC.Adaptation.AbstractAdaptor`](@ref)." adaptor::A end diff --git a/src/integrator.jl b/src/integrator.jl index 5dd69ac4..49962857 100644 --- a/src/integrator.jl +++ b/src/integrator.jl @@ -5,7 +5,7 @@ # TODO: The type `<:Tuple{Integer,Bool}` is introduced to address # https://github.com/TuringLang/Turing.jl/pull/941#issuecomment-549191813 # We might want to simplify it to `Tuple{Int,Bool}` when we figured out -# why the it behaves unexpected on Windos 32. +# why the it behaves unexpected on Windows 32. """ $(TYPEDEF) diff --git a/src/metric.jl b/src/metric.jl index 5660c140..f4585b62 100644 --- a/src/metric.jl +++ b/src/metric.jl @@ -1,3 +1,8 @@ +""" +$(TYPEDEF) + +Abstract type for preconditioning metrics. +""" abstract type AbstractMetric end _string_M⁻¹(mat::AbstractMatrix, n_chars::Int = 32) = _string_M⁻¹(diag(mat), n_chars) diff --git a/src/trajectory.jl b/src/trajectory.jl index c3896e7a..4b17422f 100644 --- a/src/trajectory.jl +++ b/src/trajectory.jl @@ -25,12 +25,28 @@ end "Returns the statistics for transition `t`." stat(t::Transition) = t.stat +""" +$(TYPEDEF) +Abstract type for HMC kernels. +""" abstract type AbstractMCMCKernel end +""" +$(TYPEDEF) +Abstract type for termination criteria for Hamiltonian trajectories, e.g. no-U-turn and fixed number of leapfrog integration steps. +""" abstract type AbstractTerminationCriterion end +""" +$(TYPEDEF) +Abstract type for a fixed number of leapfrog integration steps. +""" abstract type StaticTerminationCriterion <: AbstractTerminationCriterion end +""" +$(TYPEDEF) +Abstract type for dynamic Hamiltonian trajectory termination criteria. +""" abstract type DynamicTerminationCriterion <: AbstractTerminationCriterion end """ diff --git a/test/constructors.jl b/test/constructors.jl index 49b0cf89..d490eb11 100644 --- a/test/constructors.jl +++ b/test/constructors.jl @@ -131,9 +131,13 @@ get_kernel_hyperparamsT(spl::NUTS, state) = typeof(state.κ.τ.termination_crite @test AdvancedHMC.sampler_eltype(sampler) == T # Step. - transition, state = - AbstractMCMC.step(rng, model, sampler; n_adapts = 0, init_params = θ_init) - + transition, state = AbstractMCMC.step( + rng, + model, + sampler; + n_adapts = 0, + initial_params = θ_init, + ) # Verify that the types are preserved in the transition. @test eltype(transition.z.θ) == T @test eltype(transition.z.r) == T @@ -159,7 +163,7 @@ get_kernel_hyperparamsT(spl::NUTS, state) = typeof(state.κ.τ.termination_crite end @testset "Utils" begin - @testset "init_params" begin + @testset "initial_params" begin d = 2 θ_init = randn(d) rng = Random.default_rng() @@ -171,10 +175,10 @@ end metric = AdvancedHMC.make_metric(spl, logdensity) hamiltonian = Hamiltonian(metric, model) - init_params1 = AdvancedHMC.make_init_params(rng, spl, logdensity, nothing) - @test typeof(init_params1) == Vector{T} - @test length(init_params1) == d - init_params2 = AdvancedHMC.make_init_params(rng, spl, logdensity, θ_init) - @test init_params2 == θ_init + initial_params1 = AdvancedHMC.make_initial_params(rng, spl, logdensity, nothing) + @test typeof(initial_params1) == Vector{T} + @test length(initial_params1) == d + initial_params2 = AdvancedHMC.make_initial_params(rng, spl, logdensity, θ_init) + @test initial_params2 == θ_init end end From 8d3b3433624c7f6b7840ce21442b20bef896c698 Mon Sep 17 00:00:00 2001 From: Hong Ge <3279477+yebai@users.noreply.github.com> Date: Thu, 2 Nov 2023 22:09:13 +0000 Subject: [PATCH 06/20] Update Project.toml --- Project.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Project.toml b/Project.toml index 4fe85fe9..9dda4d3f 100644 --- a/Project.toml +++ b/Project.toml @@ -46,6 +46,8 @@ SimpleUnPack = "1.1" Statistics = "1.6" StatsBase = "0.31, 0.32, 0.33, 0.34" StatsFuns = "0.8, 0.9, 1" +LinearAlgebra = "1.6" +Random = "1.6" julia = "1.6" [extras] From 2a88729c8b185a8b096d840518dafaab4aa87d51 Mon Sep 17 00:00:00 2001 From: Hong Ge Date: Fri, 3 Nov 2023 00:23:30 +0000 Subject: [PATCH 07/20] Update README.md --- README.md | 2 +- test/abstractmcmc.jl | 10 +++++----- test/mcmcchains.jl | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 49090dc0..dffc7e97 100644 --- a/README.md +++ b/README.md @@ -141,7 +141,7 @@ samples = AbstractMCMC.sample( sampler, n_adapts + n_samples; nadapts = n_adapts, - init_params = initial_θ, + initial_params = initial_θ, ) ``` diff --git a/test/abstractmcmc.jl b/test/abstractmcmc.jl index 4d895c72..242c9f29 100644 --- a/test/abstractmcmc.jl +++ b/test/abstractmcmc.jl @@ -27,7 +27,7 @@ using Statistics: mean nuts, n_adapts + n_samples; n_adapts = n_adapts, - init_params = θ_init, + initial_params = θ_init, progress = false, verbose = false, ) @@ -50,7 +50,7 @@ using Statistics: mean hmc, n_adapts + n_samples; n_adapts = n_adapts, - init_params = θ_init, + initial_params = θ_init, progress = false, verbose = false, ) @@ -73,7 +73,7 @@ using Statistics: mean custom, n_adapts + n_samples; n_adapts = 0, - init_params = θ_init, + initial_params = θ_init, progress = false, verbose = false, ) @@ -99,7 +99,7 @@ using Statistics: mean custom, 10; n_adapts = 0, - init_params = θ_init, + initial_params = θ_init, progress = false, verbose = false, ) @@ -109,7 +109,7 @@ using Statistics: mean custom, 10; n_adapts = 0, - init_params = θ_init, + initial_params = θ_init, progress = false, verbose = false, ) diff --git a/test/mcmcchains.jl b/test/mcmcchains.jl index a555a90a..da470842 100644 --- a/test/mcmcchains.jl +++ b/test/mcmcchains.jl @@ -24,7 +24,7 @@ using Statistics: mean sampler, n_adapts + n_samples; nadapts = n_adapts, - init_params = θ_init, + initial_params = θ_init, chain_type = Chains, progress = false, bijector = invlink_gdemo, From 56aa5c88e86a77e9c47997ade907510ac7580fda Mon Sep 17 00:00:00 2001 From: Christopher Rackauckas Date: Tue, 28 Nov 2023 19:43:31 -0800 Subject: [PATCH 08/20] Allow CUDA v5 (#360) The failed CI is not related to this PR (it failed on main too) --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 9dda4d3f..1d8c19a3 100644 --- a/Project.toml +++ b/Project.toml @@ -32,7 +32,7 @@ AdvancedHMCOrdinaryDiffEqExt = "OrdinaryDiffEq" [compat] AbstractMCMC = "4.2, 5" ArgCheck = "1, 2" -CUDA = "3, 4" +CUDA = "3, 4, 5" DocStringExtensions = "0.8, 0.9" InplaceOps = "0.3" LogDensityProblems = "2" From 37f0995ea466ec5a9c9b09ecacc04c317ba77886 Mon Sep 17 00:00:00 2001 From: Kai Xu <5985769+xukai92@users.noreply.github.com> Date: Wed, 29 Nov 2023 07:58:10 -0500 Subject: [PATCH 09/20] fix: conflict of @main from Base (nightly) (#362) * fix: conflict of @main from Base (nightly) * chore: bump up version --------- Co-authored-by: Kai Xu --- Project.toml | 2 +- test/runtests.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Project.toml b/Project.toml index 1d8c19a3..efdaf2a4 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "AdvancedHMC" uuid = "0bf59076-c3b1-5ca4-86bd-e02cd72cde3d" -version = "0.6.0" +version = "0.6.1" [deps] AbstractMCMC = "80f14c24-f653-4e6a-9b94-39d6b0f70001" diff --git a/test/runtests.jl b/test/runtests.jl index 382bb871..edc9fa6f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -36,7 +36,7 @@ if GROUP == "All" || GROUP == "AdvancedHMC" @warn "Skipping GPU tests because no GPU available." end - @main function runtests(patterns...; dry::Bool = false) + Comonicon.@main function runtests(patterns...; dry::Bool = false) retest(patterns...; dry = dry, verbose = Inf) end end From bdad3e4baf53bf03cd3b230031295147d85d3af6 Mon Sep 17 00:00:00 2001 From: Markus Hauru Date: Tue, 25 Jun 2024 15:31:22 +0200 Subject: [PATCH 10/20] Fix broken links and tags in docs (#367) --- README.md | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index dffc7e97..c3a9bf93 100644 --- a/README.md +++ b/README.md @@ -35,23 +35,11 @@ If you are interested in using AdvancedHMC.jl through a probabilistic programmin This section demonstrates a minimal example of sampling from a multivariate Gaussian (10-dimensional) using the no U-turn sampler (NUTS). Below we describe the major components of the Hamiltonian system which are essential to sample using this approach: -- **Metric**: In many sampling problems the sample space is usually associated with a metric that allows us to measure the distance between any two points, and other similar quantities. In the example in this section, we use a special metric called the **Euclidean Metric**, represented with a `D × D` matrix from which we can compute distances. -
- Further details about the Metric component - The Euclidean metric is also known as the mass matrix in the physical perspective. For available metrics refer Hamiltonian mass matrix. -
- -- **Leapfrog integration**: Leapfrog integration is a second-order numerical method for integrating differential equations (In this case they are equations of motion for the relative position of one particle with respect to the other). The order of this integration signifies its rate of convergence. Any algorithm with a finite time step size will have numerical errors, and the order is related to this error. For a second-order algorithm, this error scales as the second power of the time step, hence, the name second-order. High-order integrators are usually complex to code and have a limited region of convergence; hence they do not allow arbitrarily large time steps. A second-order integrator is suitable for our purpose. Hence we opt for the leapfrog integrator. It is called `leapfrog` due to the ways this algorithm is written, where the positions and velocities of particles `leap over` each other. -
- About the leapfrog integration scheme - Suppose ${\bf x}$ and ${\bf v}$ are the position and velocity of an individual particle respectively; $i$ and $i+1$ are the indices for time values $t_i$ and $t_{i+1}$ respectively; $dt = t_{i+1} - t_i$ is the time step size (constant and regularly spaced intervals), and ${\bf a}$ is the acceleration induced on a particle by the forces of all other particles. Furthermore, suppose positions are defined at times $t_i, t_{i+1}, t_{i+2}, \dots $, spaced at constant intervals $dt$, the velocities are defined at halfway times in between, denoted by $t_{i-1/2}, t_{i+1/2}, t_{i+3/2}, \dots $, where $t_{i+1} - t_{i + 1/2} = t_{i + 1/2} - t_i = dt / 2$, and the accelerations ${\bf a}$ are defined only on integer times, just like the positions. Then the leapfrog integration scheme is given as: $x_{i} = x_{i-1} + v_{i-1/2} dt; \quad v_{i+1/2} = v_{i-1/2} + a_i dt$. For available integrators refer Integrator. -
- -- **Kernel for trajectories (static or dynamic)**: Different kernels, which may be static or dynamic, can be used. At each iteration of any variant of the HMC algorithm, there are two main steps - the first step changes the momentum and the second step may change both the position and the momentum of a particle. -
- More about the kernels - In the classical HMC approach, during the first step, new values for the momentum variables are randomly drawn from their Gaussian distribution, independently of the current values of the position variables. A Metropolis update is performed during the second step, using Hamiltonian dynamics to provide a new state. For available kernels refer kernel. -
+- **Metric**: In many sampling problems the sample space is associated with a metric that allows us to measure the distance between any two points, and other similar quantities. In the example in this section, we use a special metric called the **Euclidean Metric**, represented with a `D × D` matrix from which we can compute distances.[^1] + +- **Leapfrog integration**: Leapfrog integration is a second-order numerical method for integrating differential equations (In this case they are equations of motion for the relative position of one particle with respect to the other). The order of this integration signifies its rate of convergence. Any algorithm with a finite time step size will have numerical errors, and the order is related to this error. For a second-order algorithm, this error scales as the second power of the time step, hence, the name second-order. High-order integrators are usually complex to code and have a limited region of convergence; hence they do not allow arbitrarily large time steps. A second-order integrator is suitable for our purpose. Hence we opt for the leapfrog integrator. It is called `leapfrog` due to the ways this algorithm is written, where the positions and velocities of particles "leap over" each other.[^2] + +- **Kernel for trajectories (static or dynamic)**: Different kernels, which may be static or dynamic, can be used. At each iteration of any variant of the HMC algorithm, there are two main steps - the first step changes the momentum and the second step may change both the position and the momentum of a particle.[^3] ```julia using AdvancedHMC, ForwardDiff @@ -97,7 +85,7 @@ samples, stats = sample(hamiltonian, kernel, initial_θ, n_samples, adaptor, n_a ### Parallel sampling AdvancedHMC enables parallel sampling (either distributed or multi-thread) via Julia's [parallel computing functions](https://docs.julialang.org/en/v1/manual/parallel-computing/). -It also supports vectorized sampling for static HMC and has been discussed in more detail in the documentation [here](https://turinglang.github.io/AdvancedHMC.jl/stable/#Parallel-sampling). +It also supports vectorized sampling for static HMC. The below example utilizes the `@threads` macro to sample 4 chains across 4 threads. @@ -359,3 +347,9 @@ with the following BibTeX entry: 5. Betancourt, M. (2016). Identifying the optimal integration time in Hamiltonian Monte Carlo. [arXiv preprint arXiv:1601.00225](https://arxiv.org/abs/1601.00225). 6. Hoffman, M. D., & Gelman, A. (2014). The No-U-Turn Sampler: adaptively setting path lengths in Hamiltonian Monte Carlo. Journal of Machine Learning Research, 15(1), 1593-1623. ([arXiv](http://arxiv.org/abs/1111.4246)) + +## Footnotes + +[^1]: The Euclidean metric is also known as the mass matrix in the physical perspective. See [Hamiltonian mass matrix](#Hamiltonian-mass-matrix-(metric)) for available metrics. +[^2]: About the leapfrog integration scheme: Suppose ${\bf x}$ and ${\bf v}$ are the position and velocity of an individual particle respectively; $i$ and $i+1$ are the indices for time values $t_i$ and $t_{i+1}$ respectively; $dt = t_{i+1} - t_i$ is the time step size (constant and regularly spaced intervals), and ${\bf a}$ is the acceleration induced on a particle by the forces of all other particles. Furthermore, suppose positions are defined at times $t_i, t_{i+1}, t_{i+2}, \dots $, spaced at constant intervals $dt$, the velocities are defined at halfway times in between, denoted by $t_{i-1/2}, t_{i+1/2}, t_{i+3/2}, \dots $, where $t_{i+1} - t_{i + 1/2} = t_{i + 1/2} - t_i = dt / 2$, and the accelerations ${\bf a}$ are defined only on integer times, just like the positions. Then the leapfrog integration scheme is given as: $x_{i} = x_{i-1} + v_{i-1/2} dt; \quad v_{i+1/2} = v_{i-1/2} + a_i dt$. For available integrators refer to [Integrator](#Integrator-(integrator)). +[^3]: On kernels: In the classical HMC approach, during the first step, new values for the momentum variables are randomly drawn from their Gaussian distribution, independently of the current values of the position variables. A Metropolis update is performed during the second step, using Hamiltonian dynamics to provide a new state. For available kernels refer to [Kernel](#Kernel-(kernel)). From 61111336cbe78d845ff82f68d381ab12da507989 Mon Sep 17 00:00:00 2001 From: Jitendra Suthar <141838395+jeetsuthar@users.noreply.github.com> Date: Thu, 4 Jul 2024 19:27:51 +0530 Subject: [PATCH 11/20] added navabr workflow (#368) --- .github/workflows/DocsNav.yml | 44 +++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .github/workflows/DocsNav.yml diff --git a/.github/workflows/DocsNav.yml b/.github/workflows/DocsNav.yml new file mode 100644 index 00000000..4070ce03 --- /dev/null +++ b/.github/workflows/DocsNav.yml @@ -0,0 +1,44 @@ +name: Add Navbar + +on: + page_build: # Triggers the workflow on push events to gh-pages branch + workflow_dispatch: # Allows manual triggering + +jobs: + add-navbar: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout gh-pages + uses: actions/checkout@v4 + with: + ref: gh-pages + fetch-depth: 0 + + - name: Download insert_navbar.sh + run: | + curl -O https://raw.githubusercontent.com/TuringLang/turinglang.github.io/main/assets/scripts/insert_navbar.sh + chmod +x insert_navbar.sh + + - name: Update Navbar + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git config user.name github-actions[bot] + git config user.email github-actions[bot]@users.noreply.github.com + + # Update all HTML files in the current directory (gh-pages root) + ./insert_navbar.sh . + + # Remove the insert_navbar.sh file + rm insert_navbar.sh + + # Check if there are any changes + if [[ -n $(git status -s) ]]; then + git add . + git commit -m "Added navbar and removed insert_navbar.sh" + git push "https://${GITHUB_ACTOR}:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" gh-pages + else + echo "No changes to commit" + fi \ No newline at end of file From ecc388a069bba850260ee9b1b9ed8a6f296e3e96 Mon Sep 17 00:00:00 2001 From: Kai Xu Date: Wed, 10 Jul 2024 11:53:51 -0400 Subject: [PATCH 12/20] feat: support position-dependent kinetic (#369) * feat: support position-dependent kinetic Signed-off-by: Kai Xu * Update src/hamiltonian.jl Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update src/hamiltonian.jl Co-authored-by: Hong Ge <3279477+yebai@users.noreply.github.com> * Update src/hamiltonian.jl Co-authored-by: Hong Ge <3279477+yebai@users.noreply.github.com> * Update src/metric.jl Co-authored-by: Hong Ge <3279477+yebai@users.noreply.github.com> * Update src/metric.jl Co-authored-by: Hong Ge <3279477+yebai@users.noreply.github.com> * Update src/metric.jl Co-authored-by: Hong Ge <3279477+yebai@users.noreply.github.com> * fix: add position-independent methods back for leapfrog comptaibility Signed-off-by: Kai Xu * Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update src/metric.jl * Update src/metric.jl Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update src/metric.jl Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update src/metric.jl Co-authored-by: Hong Ge <3279477+yebai@users.noreply.github.com> --------- Signed-off-by: Kai Xu Co-authored-by: Hong Ge <3279477+yebai@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/hamiltonian.jl | 16 +++++++++++++--- src/metric.jl | 18 +++++++++++++++++- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/hamiltonian.jl b/src/hamiltonian.jl index f2bbd230..b5546051 100644 --- a/src/hamiltonian.jl +++ b/src/hamiltonian.jl @@ -45,6 +45,12 @@ end ∂H∂r(h::Hamiltonian{<:DenseEuclideanMetric,<:GaussianKinetic}, r::AbstractVecOrMat) = h.metric.M⁻¹ * r +# TODO (kai) make the order of θ and r consistent with neg_energy +# TODO (kai) add stricter types to block hamiltonian.jl#L37 from working on unknown metric/kinetic +# The gradient of a position-dependent Hamiltonian system depends on both θ and r. +∂H∂θ(h::Hamiltonian, θ::AbstractVecOrMat, r::AbstractVecOrMat) = ∂H∂θ(h, θ) +∂H∂r(h::Hamiltonian, θ::AbstractVecOrMat, r::AbstractVecOrMat) = ∂H∂r(h, r) + struct PhasePoint{T<:AbstractVecOrMat{<:AbstractFloat},V<:DualValue} θ::T # Position variables / model parameters. r::T # Momentum variables @@ -156,7 +162,7 @@ phasepoint( rng::Union{AbstractRNG,AbstractVector{<:AbstractRNG}}, θ::AbstractVecOrMat{T}, h::Hamiltonian, -) where {T<:Real} = phasepoint(h, θ, rand(rng, h.metric, h.kinetic)) +) where {T<:Real} = phasepoint(h, θ, rand(rng, h.metric, h.kinetic, θ)) abstract type AbstractMomentumRefreshment end @@ -168,7 +174,7 @@ refresh( ::FullMomentumRefreshment, h::Hamiltonian, z::PhasePoint, -) = phasepoint(h, z.θ, rand(rng, h.metric, h.kinetic)) +) = phasepoint(h, z.θ, rand(rng, h.metric, h.kinetic, z.θ)) """ $(TYPEDEF) @@ -196,4 +202,8 @@ refresh( ref::PartialMomentumRefreshment, h::Hamiltonian, z::PhasePoint, -) = phasepoint(h, z.θ, ref.α * z.r + sqrt(1 - ref.α^2) * rand(rng, h.metric, h.kinetic)) +) = phasepoint( + h, + z.θ, + ref.α * z.r + sqrt(1 - ref.α^2) * rand(rng, h.metric, h.kinetic, z.θ), +) diff --git a/src/metric.jl b/src/metric.jl index f4585b62..2afbd629 100644 --- a/src/metric.jl +++ b/src/metric.jl @@ -129,7 +129,7 @@ function _rand( return r end -# TODO The rand interface should be updated by rand from momentum distribution + optional affine transformation by metric +# TODO (kai) The rand interface should be updated as "rand from momentum distribution + optional affine transformation by metric" Base.rand(rng::AbstractRNG, metric::AbstractMetric, kinetic::AbstractKinetic) = _rand(rng, metric, kinetic) # this disambiguity is required by Random.rand Base.rand( @@ -139,3 +139,19 @@ Base.rand( ) = _rand(rng, metric, kinetic) Base.rand(metric::AbstractMetric, kinetic::AbstractKinetic) = rand(GLOBAL_RNG, metric, kinetic) + +# ignore θ by default unless defined by the specific kinetic (i.e. not position-dependent) +Base.rand( + rng::AbstractRNG, + metric::AbstractMetric, + kinetic::AbstractKinetic, + θ::AbstractVecOrMat, +) = rand(rng, metric, kinetic) # this disambiguity is required by Random.rand +Base.rand( + rng::AbstractVector{<:AbstractRNG}, + metric::AbstractMetric, + kinetic::AbstractKinetic, + θ::AbstractVecOrMat, +) = rand(rng, metric, kinetic) +Base.rand(metric::AbstractMetric, kinetic::AbstractKinetic, θ::AbstractVecOrMat) = + rand(metric, kinetic) From cfd72274bb054f863c8d4005188497cbf7c57f7b Mon Sep 17 00:00:00 2001 From: Shravan Goswami <123811742+shravanngoswamii@users.noreply.github.com> Date: Sun, 14 Jul 2024 19:45:06 +0530 Subject: [PATCH 13/20] Update DocsNav.yml (#371) --- .github/workflows/DocsNav.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/DocsNav.yml b/.github/workflows/DocsNav.yml index 4070ce03..14614d1f 100644 --- a/.github/workflows/DocsNav.yml +++ b/.github/workflows/DocsNav.yml @@ -3,6 +3,8 @@ name: Add Navbar on: page_build: # Triggers the workflow on push events to gh-pages branch workflow_dispatch: # Allows manual triggering + schedule: + - cron: '0 0 * * 0' # Runs every week on Sunday at midnight (UTC) jobs: add-navbar: @@ -27,9 +29,12 @@ jobs: run: | git config user.name github-actions[bot] git config user.email github-actions[bot]@users.noreply.github.com + + # Define the URL of the navbar to be used + NAVBAR_URL="https://raw.githubusercontent.com/TuringLang/turinglang.github.io/main/assets/scripts/TuringNavbar.html" # Update all HTML files in the current directory (gh-pages root) - ./insert_navbar.sh . + ./insert_navbar.sh . $NAVBAR_URL # Remove the insert_navbar.sh file rm insert_navbar.sh @@ -41,4 +46,4 @@ jobs: git push "https://${GITHUB_ACTOR}:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" gh-pages else echo "No changes to commit" - fi \ No newline at end of file + fi From 2b3814ccbb36806eb0f21c2c937146606a873884 Mon Sep 17 00:00:00 2001 From: Kai Xu Date: Wed, 24 Jul 2024 18:29:17 -0400 Subject: [PATCH 14/20] Generalized leapfrog integrator (#370) * feat: port generalized leapfrog Signed-off-by: Kai Xu * refactor: remove copy Signed-off-by: Kai Xu * format: add emplty line Signed-off-by: Kai Xu * Update src/riemannian/integrator.jl Co-authored-by: Hong Ge <3279477+yebai@users.noreply.github.com> * chore: add warning for using generalized leapfrog with vectorization Signed-off-by: Kai Xu * fix: type order Signed-off-by: Kai Xu --------- Signed-off-by: Kai Xu Co-authored-by: Hong Ge <3279477+yebai@users.noreply.github.com> --- src/AdvancedHMC.jl | 2 + src/riemannian/integrator.jl | 102 +++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 src/riemannian/integrator.jl diff --git a/src/AdvancedHMC.jl b/src/AdvancedHMC.jl index 42d52767..fcaab095 100644 --- a/src/AdvancedHMC.jl +++ b/src/AdvancedHMC.jl @@ -52,6 +52,8 @@ export Hamiltonian include("integrator.jl") export Leapfrog, JitteredLeapfrog, TemperedLeapfrog +include("riemannian/integrator.jl") +export GeneralizedLeapfrog include("trajectory.jl") export Trajectory, diff --git a/src/riemannian/integrator.jl b/src/riemannian/integrator.jl new file mode 100644 index 00000000..cce0dc27 --- /dev/null +++ b/src/riemannian/integrator.jl @@ -0,0 +1,102 @@ +""" +$(TYPEDEF) + +Generalized leapfrog integrator with fixed step size `ϵ`. + +# Fields + +$(TYPEDFIELDS) + + +## References + +1. Girolami, Mark, and Ben Calderhead. "Riemann manifold Langevin and Hamiltonian Monte Carlo methods." Journal of the Royal Statistical Society Series B: Statistical Methodology 73, no. 2 (2011): 123-214. +""" +struct GeneralizedLeapfrog{T<:AbstractScalarOrVec{<:AbstractFloat}} <: AbstractLeapfrog{T} + "Step size." + ϵ::T + n::Int +end +Base.show(io::IO, l::GeneralizedLeapfrog) = + print(io, "GeneralizedLeapfrog(ϵ=$(round.(l.ϵ; sigdigits=3)), n=$(l.n))") + +# fallback to ignore return_cache & cache kwargs for other ∂H∂θ +function ∂H∂θ_cache(h, θ, r; return_cache = false, cache = nothing) + dv = ∂H∂θ(h, θ, r) + return return_cache ? (dv, nothing) : dv +end + +# TODO(Kai) make sure vectorization works +# TODO(Kai) check if tempering is valid +# TODO(Kai) abstract out the 3 main steps and merge with `step` in `integrator.jl` +function step( + lf::GeneralizedLeapfrog{T}, + h::Hamiltonian, + z::P, + n_steps::Int = 1; + fwd::Bool = n_steps > 0, # simulate hamiltonian backward when n_steps < 0 + full_trajectory::Val{FullTraj} = Val(false), +) where {T<:AbstractScalarOrVec{<:AbstractFloat},TP,P<:PhasePoint{TP},FullTraj} + n_steps = abs(n_steps) # to support `n_steps < 0` cases + + ϵ = fwd ? step_size(lf) : -step_size(lf) + ϵ = ϵ' + + if !(T <: AbstractFloat) || !(TP <: AbstractVector) + @warn "Vectorization is not tested for GeneralizedLeapfrog." + end + + res = if FullTraj + Vector{P}(undef, n_steps) + else + z + end + + for i = 1:n_steps + θ_init, r_init = z.θ, z.r + # Tempering + #r = temper(lf, r, (i=i, is_half=true), n_steps) + # eq (16) of Girolami & Calderhead (2011) + r_half = r_init + local cache + for j = 1:lf.n + # Reuse cache for the first iteration + if j == 1 + @unpack value, gradient = z.ℓπ + elseif j == 2 # cache intermediate values that depends on θ only (which are unchanged) + retval, cache = ∂H∂θ_cache(h, θ_init, r_half; return_cache = true) + @unpack value, gradient = retval + else # reuse cache + @unpack value, gradient = ∂H∂θ_cache(h, θ_init, r_half; cache = cache) + end + r_half = r_init - ϵ / 2 * gradient + end + # eq (17) of Girolami & Calderhead (2011) + θ_full = θ_init + term_1 = ∂H∂r(h, θ_init, r_half) # unchanged across the loop + for j = 1:lf.n + θ_full = θ_init + ϵ / 2 * (term_1 + ∂H∂r(h, θ_full, r_half)) + end + # eq (18) of Girolami & Calderhead (2011) + @unpack value, gradient = ∂H∂θ(h, θ_full, r_half) + r_full = r_half - ϵ / 2 * gradient + # Tempering + #r = temper(lf, r, (i=i, is_half=false), n_steps) + # Create a new phase point by caching the logdensity and gradient + z = phasepoint(h, θ_full, r_full; ℓπ = DualValue(value, gradient)) + # Update result + if FullTraj + res[i] = z + else + res = z + end + if !isfinite(z) + # Remove undef + if FullTraj + res = res[isassigned.(Ref(res), 1:n_steps)] + end + break + end + end + return res +end From 0eee665183dbb801a686e87d630f2e169e935866 Mon Sep 17 00:00:00 2001 From: Jaime RZ Date: Thu, 3 Oct 2024 16:24:54 +0300 Subject: [PATCH 15/20] Fix Step (#359) * fix step * Update src/abstractmcmc.jl Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --------- Co-authored-by: Hong Ge <3279477+yebai@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/abstractmcmc.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/abstractmcmc.jl b/src/abstractmcmc.jl index 905deaf7..96ec9c7a 100644 --- a/src/abstractmcmc.jl +++ b/src/abstractmcmc.jl @@ -141,6 +141,7 @@ function AbstractMCMC.step( model::AbstractMCMC.LogDensityModel, spl::AbstractHMCSampler, state::HMCState; + n_adapts::Int = 0, kwargs..., ) # Compute transition. @@ -158,7 +159,6 @@ function AbstractMCMC.step( # Adapt h and spl. tstat = stat(t) - n_adapts = kwargs[:n_adapts] h, κ, isadapted = adapt!(h, κ, adaptor, i, n_adapts, t.z.θ, tstat.acceptance_rate) tstat = merge(tstat, (is_adapt = isadapted,)) From ba7ac8c0db2b621c62b7582744d824bce430b27b Mon Sep 17 00:00:00 2001 From: David Widmann Date: Thu, 3 Oct 2024 19:42:13 +0200 Subject: [PATCH 16/20] Use `Base.RefValue` (#374) --- src/abstractmcmc.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/abstractmcmc.jl b/src/abstractmcmc.jl index 96ec9c7a..502763a8 100644 --- a/src/abstractmcmc.jl +++ b/src/abstractmcmc.jl @@ -189,8 +189,8 @@ struct HMCProgressCallback{P} "If `progress` is not specified and this is `true` some information will be logged upon completion of adaptation." verbose::Bool "Number of divergent transitions fo far." - num_divergent_transitions::Ref{Int} - num_divergent_transitions_during_adaption::Ref{Int} + num_divergent_transitions::Base.RefValue{Int} + num_divergent_transitions_during_adaption::Base.RefValue{Int} end function HMCProgressCallback(n_samples; progress = true, verbose = false) From f1251f592f54fc7c7ba00c2b08728e02793669fc Mon Sep 17 00:00:00 2001 From: David Widmann Date: Fri, 4 Oct 2024 13:58:45 +0200 Subject: [PATCH 17/20] Require AbstractMCMC 5 (#376) * Require AbstractMCMC 5 * Clean `research/Project.toml` --- Project.toml | 2 +- research/Project.toml | 23 ----------------------- 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/Project.toml b/Project.toml index efdaf2a4..dc5f9e02 100644 --- a/Project.toml +++ b/Project.toml @@ -30,7 +30,7 @@ AdvancedHMCMCMCChainsExt = "MCMCChains" AdvancedHMCOrdinaryDiffEqExt = "OrdinaryDiffEq" [compat] -AbstractMCMC = "4.2, 5" +AbstractMCMC = "5" ArgCheck = "1, 2" CUDA = "3, 4, 5" DocStringExtensions = "0.8, 0.9" diff --git a/research/Project.toml b/research/Project.toml index 7d239b2a..94dc00e1 100644 --- a/research/Project.toml +++ b/research/Project.toml @@ -1,31 +1,8 @@ [deps] -AbstractMCMC = "80f14c24-f653-4e6a-9b94-39d6b0f70001" AdaptiveRejectionSampling = "c75e803d-635f-53bd-ab7d-544e482d8c75" -ArgCheck = "dce04be8-c92d-5529-be00-80e4d2c0e197" -DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" FiniteDiff = "6a86dc24-6348-571c-b903-95158fe2bd41" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" -InplaceOps = "505f98c9-085e-5b2c-8e89-488be7bf1f34" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" -Requires = "ae029012-a4dd-5104-9daa-d747884805df" ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267" -Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46" -SimpleUnPack = "ce78b400-467f-4804-87d8-8f486da07d0a" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" -StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" -StatsFuns = "4c63d2b9-4356-54db-8cca-17b64c39e42c" - -[compat] -AbstractMCMC = "3.2, 4" -ArgCheck = "1, 2" -DocStringExtensions = "0.8, 0.9" -InplaceOps = "0.3" -ProgressMeter = "1" -Requires = "0.5, 1" -Setfield = "0.7, 0.8, 1" -SimpleUnPack = "1" -StatsBase = "0.31, 0.32, 0.33" -StatsFuns = "0.8, 0.9, 1" -julia = "1" From 85bf5fe6d2347b8bc7079bbcf6edaff92d7b20d0 Mon Sep 17 00:00:00 2001 From: David Widmann Date: Fri, 4 Oct 2024 14:49:24 +0200 Subject: [PATCH 18/20] Use `n_adapts` instead of `nadapts` (#375) * Use `n_adapts` instead of `nadapts` * Update Project.toml * Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- Project.toml | 2 +- README.md | 2 +- src/abstractmcmc.jl | 38 +++++++++++++++++++++++++++++++++++--- test/abstractmcmc.jl | 24 ++++++++++++++++++++++++ test/mcmcchains.jl | 2 +- 5 files changed, 62 insertions(+), 6 deletions(-) diff --git a/Project.toml b/Project.toml index dc5f9e02..a3c51910 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "AdvancedHMC" uuid = "0bf59076-c3b1-5ca4-86bd-e02cd72cde3d" -version = "0.6.1" +version = "0.6.2" [deps] AbstractMCMC = "80f14c24-f653-4e6a-9b94-39d6b0f70001" diff --git a/README.md b/README.md index c3a9bf93..f16830b7 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,7 @@ samples = AbstractMCMC.sample( model, sampler, n_adapts + n_samples; - nadapts = n_adapts, + n_adapts = n_adapts, initial_params = initial_θ, ) ``` diff --git a/src/abstractmcmc.jl b/src/abstractmcmc.jl index 502763a8..24ce799c 100644 --- a/src/abstractmcmc.jl +++ b/src/abstractmcmc.jl @@ -47,6 +47,14 @@ function AbstractMCMC.sample( callback = nothing, kwargs..., ) + if haskey(kwargs, :nadapts) + throw( + ArgumentError( + "keyword argument `nadapts` is unsupported. Please use `n_adapts` to specify the number of adaptation steps.", + ), + ) + end + if callback === nothing callback = HMCProgressCallback(N, progress = progress, verbose = verbose) progress = false # don't use AMCMC's progress-funtionality @@ -78,6 +86,13 @@ function AbstractMCMC.sample( callback = nothing, kwargs..., ) + if haskey(kwargs, :nadapts) + throw( + ArgumentError( + "keyword argument `nadapts` is unsupported. Please use `n_adapts` to specify the number of adaptation steps.", + ), + ) + end if callback === nothing callback = HMCProgressCallback(N, progress = progress, verbose = verbose) @@ -144,6 +159,14 @@ function AbstractMCMC.step( n_adapts::Int = 0, kwargs..., ) + if haskey(kwargs, :nadapts) + throw( + ArgumentError( + "keyword argument `nadapts` is unsupported. Please use `n_adapts` to specify the number of adaptation steps.", + ), + ) + end + # Compute transition. i = state.i + 1 t_old = state.transition @@ -200,7 +223,16 @@ function HMCProgressCallback(n_samples; progress = true, verbose = false) HMCProgressCallback(pm, progress, verbose, Ref(0), Ref(0)) end -function (cb::HMCProgressCallback)(rng, model, spl, t, state, i; nadapts = 0, kwargs...) +function (cb::HMCProgressCallback)( + rng, + model, + spl, + t, + state, + i; + n_adapts::Int = 0, + kwargs..., +) progress = cb.progress verbose = cb.verbose pm = cb.pm @@ -243,8 +275,8 @@ function (cb::HMCProgressCallback)(rng, model, spl, t, state, i; nadapts = 0, kw ), ) # Report finish of adapation - elseif verbose && isadapted && i == nadapts - @info "Finished $nadapts adapation steps" adaptor κ.τ.integrator metric + elseif verbose && isadapted && i == n_adapts + @info "Finished $(n_adapts) adapation steps" adaptor κ.τ.integrator metric end end diff --git a/test/abstractmcmc.jl b/test/abstractmcmc.jl index 242c9f29..25359cd6 100644 --- a/test/abstractmcmc.jl +++ b/test/abstractmcmc.jl @@ -32,6 +32,30 @@ using Statistics: mean verbose = false, ) + # Error if keyword argument `nadapts` is used + @test_throws ArgumentError AbstractMCMC.sample( + rng, + model, + nuts, + n_adapts + n_samples; + nadapts = n_adapts, + initial_params = θ_init, + progress = false, + verbose = false, + ) + @test_throws ArgumentError AbstractMCMC.sample( + rng, + model, + nuts, + MCMCThreads(), + n_adapts + n_samples, + 2; + nadapts = n_adapts, + initial_params = θ_init, + progress = false, + verbose = false, + ) + # Transform back to original space. # NOTE: We're not correcting for the `logabsdetjac` here since, but # we're only interested in the mean it doesn't matter. diff --git a/test/mcmcchains.jl b/test/mcmcchains.jl index da470842..1f868578 100644 --- a/test/mcmcchains.jl +++ b/test/mcmcchains.jl @@ -23,7 +23,7 @@ using Statistics: mean model, sampler, n_adapts + n_samples; - nadapts = n_adapts, + n_adapts = n_adapts, initial_params = θ_init, chain_type = Chains, progress = false, From 47b212ab2eb9ec3fe804ce5b181a6de2b257be4e Mon Sep 17 00:00:00 2001 From: David Widmann Date: Sun, 6 Oct 2024 13:04:54 +0200 Subject: [PATCH 19/20] Update GH actions and add dependabot (#377) * Update GH actions and add dependabot * Update Julia compat (tests pass with 1.6.7?) --- .github/dependabot.yml | 7 +++++ .github/workflows/CI.yml | 37 ++++++++++++------------- .github/workflows/ExperimentalTests.yml | 27 ++++++++++-------- .github/workflows/Format.yml | 5 ++-- .github/workflows/IntegrationTests.yml | 27 ++++++++++-------- .github/workflows/documentation.yml | 9 +++--- Project.toml | 2 +- 7 files changed, 63 insertions(+), 51 deletions(-) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..d60f0707 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" # Location of package manifests + schedule: + interval: "monthly" diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 65d899c9..1484ec36 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -6,42 +6,41 @@ on: - master pull_request: +concurrency: + # Skip intermediate builds: always. + # Cancel intermediate builds: only if it is a pull request build. + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} + jobs: test: + # needed to allow julia-actions/cache to delete old caches that it has created + permissions: + actions: write + contents: read runs-on: ${{ matrix.os }} - continue-on-error: ${{ matrix.version == 'nightly' }} + continue-on-error: ${{ matrix.version == 'pre' }} strategy: matrix: version: - - '1.6' + - 'min' - '1' - - 'nightly' + - 'pre' os: - ubuntu-latest - macOS-latest - windows-latest arch: - - x86 - x64 - exclude: - - os: ubuntu-latest - arch: x86 - - os: macOS-latest - arch: x86 - - os: windows-latest - arch: x86 - # GitHub Action seems to have issue of running julia-nightly with windows-latest - # TODO Revisit in the future - - version: 'nightly' - os: windows-latest steps: - - uses: actions/checkout@v2 - - uses: julia-actions/setup-julia@v1 + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v2 with: version: ${{ matrix.version }} arch: ${{ matrix.arch }} - - uses: julia-actions/julia-buildpkg@latest + - uses: julia-actions/cache@v2 + - uses: julia-actions/julia-buildpkg@v1 - name: Run tests - uses: julia-actions/julia-runtest@latest + uses: julia-actions/julia-runtest@v1 env: AHMC_TEST_GROUP: AdvancedHMC diff --git a/.github/workflows/ExperimentalTests.yml b/.github/workflows/ExperimentalTests.yml index 49ed1e77..a605107f 100644 --- a/.github/workflows/ExperimentalTests.yml +++ b/.github/workflows/ExperimentalTests.yml @@ -6,8 +6,18 @@ on: - master pull_request: +concurrency: + # Skip intermediate builds: always. + # Cancel intermediate builds: only if it is a pull request build. + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} + jobs: test: + # needed to allow julia-actions/cache to delete old caches that it has created + permissions: + actions: write + contents: read runs-on: ${{ matrix.os }} strategy: matrix: @@ -18,23 +28,16 @@ jobs: - macOS-latest - windows-latest arch: - - x86 - x64 - exclude: - - os: ubuntu-latest - arch: x86 - - os: macOS-latest - arch: x86 - - os: windows-latest - arch: x86 steps: - - uses: actions/checkout@v2 - - uses: julia-actions/setup-julia@v1 + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v2 with: version: ${{ matrix.version }} arch: ${{ matrix.arch }} - - uses: julia-actions/julia-buildpkg@latest + - uses: julia-actions/cache@v2 + - uses: julia-actions/julia-buildpkg@v1 - name: Run integration tests - uses: julia-actions/julia-runtest@latest + uses: julia-actions/julia-runtest@v1 env: AHMC_TEST_GROUP: Experimental diff --git a/.github/workflows/Format.yml b/.github/workflows/Format.yml index 5bdaf949..0137f5e8 100644 --- a/.github/workflows/Format.yml +++ b/.github/workflows/Format.yml @@ -5,7 +5,6 @@ on: push: branches: - master - - main concurrency: # Skip intermediate builds: always. @@ -17,8 +16,8 @@ jobs: format: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: julia-actions/setup-julia@latest + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v2 with: version: 1 - name: Format code diff --git a/.github/workflows/IntegrationTests.yml b/.github/workflows/IntegrationTests.yml index 1eb8053a..383c91d4 100644 --- a/.github/workflows/IntegrationTests.yml +++ b/.github/workflows/IntegrationTests.yml @@ -6,8 +6,18 @@ on: - master pull_request: +concurrency: + # Skip intermediate builds: always. + # Cancel intermediate builds: only if it is a pull request build. + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} + jobs: test: + # needed to allow julia-actions/cache to delete old caches that it has created + permissions: + actions: write + contents: read runs-on: ${{ matrix.os }} strategy: matrix: @@ -18,23 +28,16 @@ jobs: - macOS-latest - windows-latest arch: - - x86 - x64 - exclude: - - os: ubuntu-latest - arch: x86 - - os: macOS-latest - arch: x86 - - os: windows-latest - arch: x86 steps: - - uses: actions/checkout@v2 - - uses: julia-actions/setup-julia@v1 + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v2 with: version: ${{ matrix.version }} arch: ${{ matrix.arch }} - - uses: julia-actions/julia-buildpkg@latest + - uses: julia-actions/cache@v2 + - uses: julia-actions/julia-buildpkg@v1 - name: Run integration tests - uses: julia-actions/julia-runtest@latest + uses: julia-actions/julia-runtest@v1 env: AHMC_TEST_GROUP: Downstream diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index b8701c9b..b8652f3f 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -9,12 +9,14 @@ on: jobs: build: + permissions: + statuses: write # Used to report documentation build statuses runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: julia-actions/setup-julia@latest + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v2 with: - version: '1.7' + version: '1' - name: Install dependencies run: julia --project=docs/ -e ' using Pkg; @@ -24,4 +26,3 @@ jobs: env: DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} # If authenticating with SSH deploy key run: julia --project=docs/ docs/make.jl - diff --git a/Project.toml b/Project.toml index a3c51910..fa49a335 100644 --- a/Project.toml +++ b/Project.toml @@ -48,7 +48,7 @@ StatsBase = "0.31, 0.32, 0.33, 0.34" StatsFuns = "0.8, 0.9, 1" LinearAlgebra = "1.6" Random = "1.6" -julia = "1.6" +julia = "1.6.7" [extras] CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" From 5d5690271077826d9c0ddb2b35a5af74efc815fc Mon Sep 17 00:00:00 2001 From: Xianda Sun <5433119+sunxd3@users.noreply.github.com> Date: Thu, 31 Oct 2024 13:08:47 +0000 Subject: [PATCH 20/20] Add `getparams` and `setparams!!` following AbstractMCMC v5.5 and v5.6 (#378) * add `getparams` and `setparams!!` * undo formatting * Update test/abstractmcmc.jl Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * add some new tests * update `setparams!!` * Update src/abstractmcmc.jl Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * add comment * Update abstractmcmc.jl Co-authored-by: Hong Ge <3279477+yebai@users.noreply.github.com> * format * update implementation * bump AbstractMCMC * update test * Update src/abstractmcmc.jl Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * fix method ambiguity * Update src/abstractmcmc.jl Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update src/abstractmcmc.jl Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * fix test error * fix more test error --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Hong Ge <3279477+yebai@users.noreply.github.com> --- Project.toml | 4 ++-- research/tests/runtests.jl | 2 +- src/abstractmcmc.jl | 18 ++++++++++++++++++ test/abstractmcmc.jl | 20 ++++++++++++++++++++ 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/Project.toml b/Project.toml index fa49a335..f35b1df4 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "AdvancedHMC" uuid = "0bf59076-c3b1-5ca4-86bd-e02cd72cde3d" -version = "0.6.2" +version = "0.6.3" [deps] AbstractMCMC = "80f14c24-f653-4e6a-9b94-39d6b0f70001" @@ -30,7 +30,7 @@ AdvancedHMCMCMCChainsExt = "MCMCChains" AdvancedHMCOrdinaryDiffEqExt = "OrdinaryDiffEq" [compat] -AbstractMCMC = "5" +AbstractMCMC = "5.6" ArgCheck = "1, 2" CUDA = "3, 4, 5" DocStringExtensions = "0.8, 0.9" diff --git a/research/tests/runtests.jl b/research/tests/runtests.jl index 803458c6..2bb8e8d3 100644 --- a/research/tests/runtests.jl +++ b/research/tests/runtests.jl @@ -11,6 +11,6 @@ include("../src/riemannian_hmc.jl") include("relativistic_hmc.jl") include("riemannian_hmc.jl") -@main function runtests(patterns...; dry::Bool = false) +Comonicon.@main function runtests(patterns...; dry::Bool = false) retest(patterns...; dry = dry, verbose = Inf) end diff --git a/src/abstractmcmc.jl b/src/abstractmcmc.jl index 24ce799c..40585909 100644 --- a/src/abstractmcmc.jl +++ b/src/abstractmcmc.jl @@ -30,6 +30,24 @@ getadaptor(state::HMCState) = state.adaptor getmetric(state::HMCState) = state.metric getintegrator(state::HMCState) = state.κ.τ.integrator +function AbstractMCMC.getparams(state::HMCState) + return state.transition.z.θ +end + +function AbstractMCMC.setparams!!( + model::AbstractMCMC.LogDensityModel, + state::HMCState, + params, +) + hamiltonian = AdvancedHMC.Hamiltonian(state.metric, model) + return Setfield.@set state.transition.z = AdvancedHMC.phasepoint( + hamiltonian, + params, + state.transition.z.r; + ℓκ = state.transition.z.ℓκ, + ) +end + """ $(TYPEDSIGNATURES) diff --git a/test/abstractmcmc.jl b/test/abstractmcmc.jl index 25359cd6..7d325f03 100644 --- a/test/abstractmcmc.jl +++ b/test/abstractmcmc.jl @@ -21,6 +21,26 @@ using Statistics: mean LogDensityProblemsAD.ADgradient(Val(:ForwardDiff), ℓπ_gdemo), ) + @testset "getparams and setparams!!" begin + t, s = AbstractMCMC.step(rng, model, nuts;) + + θ = AbstractMCMC.getparams(s) + @test θ == t.z.θ + new_state = AbstractMCMC.setparams!!(model, s, θ) + @test new_state.transition.z.θ == θ + new_state_logπ = new_state.transition.z.ℓπ + @test new_state_logπ.value == s.transition.z.ℓπ.value + @test new_state_logπ.gradient == s.transition.z.ℓπ.gradient + new_state_logκ = new_state.transition.z.ℓκ + @test new_state_logκ.value == s.transition.z.ℓκ.value + @test new_state_logκ.gradient == s.transition.z.ℓκ.gradient + @test new_state.transition.z.r == s.transition.z.r + + new_θ = randn(rng, 2) + new_state = AbstractMCMC.setparams!!(model, s, new_θ) + @test AbstractMCMC.getparams(new_state) == new_θ + end + samples_nuts = AbstractMCMC.sample( rng, model,