From 19063d7c4010c202a048b93171d211199fe07bb8 Mon Sep 17 00:00:00 2001 From: Seth Axen Date: Tue, 12 Aug 2025 15:43:03 +0200 Subject: [PATCH 1/9] Make AdvancedHMC a weakdep --- Project.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Project.toml b/Project.toml index 2feaa60d..ab603c8b 100644 --- a/Project.toml +++ b/Project.toml @@ -5,6 +5,7 @@ version = "0.9.17" [deps] ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" +AdvancedHMC = "0bf59076-c3b1-5ca4-86bd-e02cd72cde3d" Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" Folds = "41a02a25-b8f0-4f67-bc48-60067656b558" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" @@ -26,18 +27,21 @@ Transducers = "28d57a85-8fef-5791-bfe6-a80928e7c999" [weakdeps] Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697" +AdvancedHMC = "0bf59076-c3b1-5ca4-86bd-e02cd72cde3d" DynamicHMC = "bbc10e6e-7c05-544b-b16e-64fede858acb" DynamicPPL = "366bfd00-2699-11ea-058f-f148b4cae6d8" MCMCChains = "c7f686f2-ff18-58e9-bc7b-31028e88f75d" Turing = "fce5fe82-541a-59a6-adf8-730c64b5f9a0" [extensions] +PathfinderAdvancedHMCExt = "AdvancedHMC" PathfinderDynamicHMCExt = "DynamicHMC" PathfinderTuringExt = ["Accessors", "DynamicPPL", "MCMCChains", "Turing"] [compat] ADTypes = "0.2.5, 1" Accessors = "0.1.12" +AdvancedHMC = "0.6" Distributions = "0.25.87" DynamicHMC = "3.4.0" DynamicPPL = "0.25.2, 0.27, 0.28, 0.29, 0.30, 0.31, 0.32, 0.33, 0.34, 0.35" From 270b1d76f4d8093e9c206544197538587c6d7db8 Mon Sep 17 00:00:00 2001 From: Seth Axen Date: Tue, 12 Aug 2025 15:44:59 +0200 Subject: [PATCH 2/9] Make AdvancedHMC integration an extension --- Project.toml | 2 -- .../PathfinderAdvancedHMCExt.jl | 29 +++++++++---------- src/Pathfinder.jl | 9 ++---- 3 files changed, 15 insertions(+), 25 deletions(-) rename src/integration/advancedhmc.jl => ext/PathfinderAdvancedHMCExt.jl (73%) diff --git a/Project.toml b/Project.toml index ab603c8b..fb65650f 100644 --- a/Project.toml +++ b/Project.toml @@ -19,7 +19,6 @@ PDMats = "90014a1f-27ba-587c-ab20-58faa44d9150" PSIS = "ce719bf2-d5d0-4fb9-925d-10a81b42ad04" ProgressLogging = "33c8b6b6-d38a-422a-b730-caa89a2f386c" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" -Requires = "ae029012-a4dd-5104-9daa-d747884805df" SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" @@ -59,7 +58,6 @@ PDMats = "0.11.35" PSIS = "0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9" ProgressLogging = "0.1.4" Random = "1" -Requires = "1.1" ReverseDiff = "1.15" SciMLBase = "2.30" Statistics = "1" diff --git a/src/integration/advancedhmc.jl b/ext/PathfinderAdvancedHMCExt.jl similarity index 73% rename from src/integration/advancedhmc.jl rename to ext/PathfinderAdvancedHMCExt.jl index f48cb1db..510051c6 100644 --- a/src/integration/advancedhmc.jl +++ b/ext/PathfinderAdvancedHMCExt.jl @@ -1,5 +1,10 @@ -using .AdvancedHMC: AdvancedHMC -using .Random +module PathfinderAdvancedHMCExt + +using AdvancedHMC: AdvancedHMC +using Pathfinder: Pathfinder +using LinearAlgebra: Diagonal, diag +using PDMats: PDMats +using Random: Random """ RankUpdateEuclideanMetric{T,M} <: AdvancedHMC.AbstractMetric @@ -35,24 +40,14 @@ See also: The AdvancedHMC [metric](@extref AdvancedHMC hamiltonian_mm) documenta """ RankUpdateEuclideanMetric -struct RankUpdateEuclideanMetric{T,M<:WoodburyPDMat{T,<:Diagonal{T}}} <: +struct RankUpdateEuclideanMetric{T,M<:Pathfinder.WoodburyPDMat{T,<:Diagonal{T}}} <: AdvancedHMC.AbstractMetric M⁻¹::M end -function RankUpdateEuclideanMetric(n::Int) - M⁻¹ = WoodburyPDMat(Diagonal(ones(n)), zeros(n, 0), zeros(0, 0)) +function Pathfinder.RankUpdateEuclideanMetric(M⁻¹::Pathfinder.WoodburyPDMat) return RankUpdateEuclideanMetric(M⁻¹) end -function RankUpdateEuclideanMetric(::Type{T}, D::Int) where {T} - return RankUpdateEuclideanMetric( - WoodburyPDMat(Diagonal(ones(T, D)), Matrix{T}(undef, D, 0), Matrix{T}(undef, 0, 0)) - ) -end -function RankUpdateEuclideanMetric(::Type{T}, sz::Tuple{Int}) where {T} - return RankUpdateEuclideanMetric(T, first(sz)) -end -RankUpdateEuclideanMetric(sz::Tuple{Int}) = RankUpdateEuclideanMetric(Float64, sz) AdvancedHMC.renew(::RankUpdateEuclideanMetric, M⁻¹) = RankUpdateEuclideanMetric(M⁻¹) @@ -66,10 +61,10 @@ function Base.show(io::IO, metric::RankUpdateEuclideanMetric) end function Base.rand( - rng::AbstractRNG, metric::RankUpdateEuclideanMetric{T}, ::AdvancedHMC.GaussianKinetic + rng::Random.AbstractRNG, metric::RankUpdateEuclideanMetric{T}, ::AdvancedHMC.GaussianKinetic ) where {T} M⁻¹ = metric.M⁻¹ - r = randn(rng, T, size(metric)...) + r = Random.randn(rng, T, size(metric)...) PDMats.invunwhiten!(r, M⁻¹, r) return r end @@ -88,3 +83,5 @@ function AdvancedHMC.∂H∂r( ) return h.metric.M⁻¹ * r end + +end # module diff --git a/src/Pathfinder.jl b/src/Pathfinder.jl index 639df94c..27a99d97 100644 --- a/src/Pathfinder.jl +++ b/src/Pathfinder.jl @@ -13,7 +13,6 @@ using PDMats: PDMats using ProgressLogging: ProgressLogging using PSIS: PSIS using Random -using Requires: Requires using SciMLBase: SciMLBase using Statistics: Statistics using StatsBase: StatsBase @@ -39,6 +38,8 @@ end # We depend on Optim, and Optim depends on ForwardDiff, so we can offer it as a default. default_ad() = ADTypes.AutoForwardDiff() +function RankUpdateEuclideanMetric end + include("transducers.jl") include("woodbury.jl") include("optimize.jl") @@ -49,10 +50,4 @@ include("resample.jl") include("singlepath.jl") include("multipath.jl") -function __init__() - Requires.@require AdvancedHMC = "0bf59076-c3b1-5ca4-86bd-e02cd72cde3d" begin - include("integration/advancedhmc.jl") - end -end - end From 2b34aad9004f2bc40a3cd41b3c8f2e2da04cd420 Mon Sep 17 00:00:00 2001 From: Seth Axen Date: Tue, 12 Aug 2025 15:45:38 +0200 Subject: [PATCH 3/9] Stop testing constructors we don't support anymore --- test/integration/AdvancedHMC/runtests.jl | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/test/integration/AdvancedHMC/runtests.jl b/test/integration/AdvancedHMC/runtests.jl index 262c0dc1..8800129e 100644 --- a/test/integration/AdvancedHMC/runtests.jl +++ b/test/integration/AdvancedHMC/runtests.jl @@ -75,21 +75,6 @@ end r = randn(5) θ = randn(5) - metric2 = Pathfinder.RankUpdateEuclideanMetric(3) - @test metric2.M⁻¹ ≈ I - @test size(metric2) == (3,) - @test size(metric2, 2) == 1 - @test eltype(metric2) === Float64 - metric2 = Pathfinder.RankUpdateEuclideanMetric((4,)) - @test metric2.M⁻¹ ≈ I - @test size(metric2) == (4,) - @test size(metric2, 2) == 1 - metric2 = Pathfinder.RankUpdateEuclideanMetric(Float32, (4,)) - @test metric2.M⁻¹ ≈ I - @test size(metric2) == (4,) - @test size(metric2, 2) == 1 - @test eltype(metric2.M⁻¹) === Float32 - @test size(metric) == (5,) @test size(metric, 2) == 1 @test AdvancedHMC.renew(metric, M⁻¹2).M⁻¹ === M⁻¹2 From 46bc1425e769b372a7516333bcd08e3ec5104d18 Mon Sep 17 00:00:00 2001 From: Seth Axen Date: Tue, 12 Aug 2025 15:51:19 +0200 Subject: [PATCH 4/9] Deprecate old constructor and document new one --- docs/src/examples/initializing-hmc.md | 5 +++-- docs/src/examples/turing.md | 2 +- ext/PathfinderAdvancedHMCExt.jl | 23 ++++++++++------------- test/integration/AdvancedHMC/runtests.jl | 5 +++-- 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/docs/src/examples/initializing-hmc.md b/docs/src/examples/initializing-hmc.md index 61584df0..c67ae3d7 100644 --- a/docs/src/examples/initializing-hmc.md +++ b/docs/src/examples/initializing-hmc.md @@ -209,11 +209,12 @@ samples_ahmc2, stats_ahmc2 = sample( ### Use Pathfinder's metric estimate for sampling -To use Pathfinder's metric with no metric adaptation, we need to use Pathfinder's own [`Pathfinder.RankUpdateEuclideanMetric`](@ref) type, which just wraps our inverse metric estimate for use with AdvancedHMC: +To use Pathfinder's metric with no metric adaptation, we need to use Pathfinder's own [`RankUpdateEuclideanMetric`](@ref) type, which just wraps our inverse metric estimate for use with AdvancedHMC. +We can construct this metric by calling `AdvancedHMC.AbstractMetric`: ```@example 1 nadapts = 75 -metric = Pathfinder.RankUpdateEuclideanMetric(inv_metric) +metric = AdvancedHMC.AbstractMetric(inv_metric) hamiltonian = Hamiltonian(metric, ∇P) ϵ = find_good_stepsize(hamiltonian, init_params) integrator = Leapfrog(ϵ) diff --git a/docs/src/examples/turing.md b/docs/src/examples/turing.md index 09c3fba7..966d537d 100644 --- a/docs/src/examples/turing.md +++ b/docs/src/examples/turing.md @@ -56,7 +56,7 @@ We can use Pathfinder's estimate of the metric and only perform enough warm-up t ```@example 1 inv_metric = result_multi.pathfinder_results[1].fit_distribution.Σ -metric = Pathfinder.RankUpdateEuclideanMetric(inv_metric) +metric = AdvancedHMC.AbstractMetric(inv_metric) kernel = HMCKernel(Trajectory{MultinomialTS}(Leapfrog(0.0), GeneralisedNoUTurn())) adaptor = StepSizeAdaptor(0.8, 1.0) # adapt only the step size nuts = AdvancedHMC.HMCSampler(kernel, metric, adaptor) diff --git a/ext/PathfinderAdvancedHMCExt.jl b/ext/PathfinderAdvancedHMCExt.jl index 510051c6..0a9eeb84 100644 --- a/ext/PathfinderAdvancedHMCExt.jl +++ b/ext/PathfinderAdvancedHMCExt.jl @@ -12,27 +12,20 @@ using Random: Random A Gaussian Euclidean metric (mass matrix) whose inverse is constructed by rank-updates. -# Constructors - - RankUpdateEuclideanMetric(n::Int) - RankUpdateEuclideanMetric(M⁻¹::Pathfinder.WoodburyPDMat) - -Construct a Gaussian Euclidean metric of size `(n, n)` with inverse of `M⁻¹`. +To construct this metric, call `AdvancedHMC.AbstractMetric` with a +[`Pathfinder.WoodburyPDMat`](@ref) as the argument. # Example ```jldoctest julia> using LinearAlgebra, Pathfinder, AdvancedHMC -julia> Pathfinder.RankUpdateEuclideanMetric(3) -RankUpdateEuclideanMetric(diag=[1.0, 1.0, 1.0]) - julia> W = Pathfinder.WoodburyPDMat(Diagonal([0.1, 0.2]), [0.7 0.2]', Diagonal([0.3])) 2×2 Pathfinder.WoodburyPDMat{Float64, Diagonal{Float64, Vector{Float64}}, Adjoint{Float64, Matrix{Float64}}, Diagonal{Float64, Vector{Float64}}, Diagonal{Float64, Vector{Float64}}, QRCompactWYQ{Float64, Matrix{Float64}, Matrix{Float64}}, UpperTriangular{Float64, Matrix{Float64}}}: 0.247 0.042 0.042 0.212 -julia> Pathfinder.RankUpdateEuclideanMetric(W) +julia> AdvancedHMC.AbstractMetric(W) RankUpdateEuclideanMetric(diag=[0.247, 0.21200000000000002]) See also: The AdvancedHMC [metric](@extref AdvancedHMC hamiltonian_mm) documentation. @@ -45,9 +38,13 @@ struct RankUpdateEuclideanMetric{T,M<:Pathfinder.WoodburyPDMat{T,<:Diagonal{T}}} M⁻¹::M end -function Pathfinder.RankUpdateEuclideanMetric(M⁻¹::Pathfinder.WoodburyPDMat) - return RankUpdateEuclideanMetric(M⁻¹) -end +Base.@deprecate( + Pathfinder.RankUpdateEuclideanMetric(M⁻¹::Pathfinder.WoodburyPDMat), + AdvancedHMC.AbstractMetric(M⁻¹), + false, +) + +AdvancedHMC.AbstractMetric(M⁻¹::Pathfinder.WoodburyPDMat) = RankUpdateEuclideanMetric(M⁻¹) AdvancedHMC.renew(::RankUpdateEuclideanMetric, M⁻¹) = RankUpdateEuclideanMetric(M⁻¹) diff --git a/test/integration/AdvancedHMC/runtests.jl b/test/integration/AdvancedHMC/runtests.jl index 8800129e..21b5ee08 100644 --- a/test/integration/AdvancedHMC/runtests.jl +++ b/test/integration/AdvancedHMC/runtests.jl @@ -67,8 +67,9 @@ end ∂ℓπ∂θ(x) = -x @testset "RankUpdateEuclideanMetric" begin - metric = Pathfinder.RankUpdateEuclideanMetric(M⁻¹) + metric = @test_deprecated Pathfinder.RankUpdateEuclideanMetric(M⁻¹) @test metric.M⁻¹ === M⁻¹ + @test metric === AdvancedHMC.AbstractMetric(M⁻¹) metric_dense = AdvancedHMC.DenseEuclideanMetric(Symmetric(Matrix(M⁻¹))) h = AdvancedHMC.Hamiltonian(metric, ℓπ, ∂ℓπ∂θ) h_dense = AdvancedHMC.Hamiltonian(metric_dense, ℓπ, ∂ℓπ∂θ) @@ -163,7 +164,7 @@ end end @testset "Initial point and final metric" begin - metric = Pathfinder.RankUpdateEuclideanMetric(result_pf.fit_distribution.Σ) + metric = AdvancedHMC.AbstractMetric(result_pf.fit_distribution.Σ) hamiltonian = Hamiltonian(metric, ∇P) ϵ = find_good_stepsize(hamiltonian, θ₀) integrator = Leapfrog(ϵ) From bdd02e2e52650ee9017171d54e40432728544927 Mon Sep 17 00:00:00 2001 From: Seth Axen Date: Tue, 12 Aug 2025 15:51:27 +0200 Subject: [PATCH 5/9] Run formatter --- ext/PathfinderAdvancedHMCExt.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ext/PathfinderAdvancedHMCExt.jl b/ext/PathfinderAdvancedHMCExt.jl index 0a9eeb84..c0028628 100644 --- a/ext/PathfinderAdvancedHMCExt.jl +++ b/ext/PathfinderAdvancedHMCExt.jl @@ -58,7 +58,9 @@ function Base.show(io::IO, metric::RankUpdateEuclideanMetric) end function Base.rand( - rng::Random.AbstractRNG, metric::RankUpdateEuclideanMetric{T}, ::AdvancedHMC.GaussianKinetic + rng::Random.AbstractRNG, + metric::RankUpdateEuclideanMetric{T}, + ::AdvancedHMC.GaussianKinetic, ) where {T} M⁻¹ = metric.M⁻¹ r = Random.randn(rng, T, size(metric)...) From 7cd1e874b4817313d733c8c30c9d361c5a665814 Mon Sep 17 00:00:00 2001 From: Seth Axen Date: Tue, 12 Aug 2025 17:09:51 +0200 Subject: [PATCH 6/9] Repair docstring example --- ext/PathfinderAdvancedHMCExt.jl | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ext/PathfinderAdvancedHMCExt.jl b/ext/PathfinderAdvancedHMCExt.jl index c0028628..facd38e2 100644 --- a/ext/PathfinderAdvancedHMCExt.jl +++ b/ext/PathfinderAdvancedHMCExt.jl @@ -20,16 +20,13 @@ To construct this metric, call `AdvancedHMC.AbstractMetric` with a ```jldoctest julia> using LinearAlgebra, Pathfinder, AdvancedHMC -julia> W = Pathfinder.WoodburyPDMat(Diagonal([0.1, 0.2]), [0.7 0.2]', Diagonal([0.3])) -2×2 Pathfinder.WoodburyPDMat{Float64, Diagonal{Float64, Vector{Float64}}, Adjoint{Float64, Matrix{Float64}}, Diagonal{Float64, Vector{Float64}}, Diagonal{Float64, Vector{Float64}}, QRCompactWYQ{Float64, Matrix{Float64}, Matrix{Float64}}, UpperTriangular{Float64, Matrix{Float64}}}: - 0.247 0.042 - 0.042 0.212 +julia> W = Pathfinder.WoodburyPDMat(Diagonal([0.1, 0.2]), [0.7 0.2]', Diagonal([0.3])); julia> AdvancedHMC.AbstractMetric(W) RankUpdateEuclideanMetric(diag=[0.247, 0.21200000000000002]) +``` See also: The AdvancedHMC [metric](@extref AdvancedHMC hamiltonian_mm) documentation. -``` """ RankUpdateEuclideanMetric From 5ab7047c4c37d0d42038692c2e320d632a3f4d29 Mon Sep 17 00:00:00 2001 From: Seth Axen Date: Tue, 12 Aug 2025 17:10:20 +0200 Subject: [PATCH 7/9] Add RankUpdateEuclideanMetric to public API docs --- docs/make.jl | 5 ++++- docs/src/examples/initializing-hmc.md | 2 +- docs/src/lib/public.md | 8 ++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/make.jl b/docs/make.jl index 35f69aae..c53a3040 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,8 +1,11 @@ +using AdvancedHMC # triggering loading of PathfinderAdvancedHMCExt using Pathfinder using Documenter using DocumenterCitations using DocumenterInterLinks +PathfinderAdvancedHMCExt = Base.get_extension(Pathfinder, :PathfinderAdvancedHMCExt) + DocMeta.setdocmeta!(Pathfinder, :DocTestSetup, :(using Pathfinder); recursive=true) bib = CitationBibliography(joinpath(@__DIR__, "src", "references.bib"); style=:numeric) @@ -37,7 +40,7 @@ links = InterLinks( ) makedocs(; - modules=[Pathfinder], + modules=[Pathfinder, PathfinderAdvancedHMCExt], authors="Seth Axen and contributors", repo=Remotes.GitHub("mlcolab", "Pathfinder.jl"), sitename="Pathfinder.jl", diff --git a/docs/src/examples/initializing-hmc.md b/docs/src/examples/initializing-hmc.md index c67ae3d7..7242171f 100644 --- a/docs/src/examples/initializing-hmc.md +++ b/docs/src/examples/initializing-hmc.md @@ -209,7 +209,7 @@ samples_ahmc2, stats_ahmc2 = sample( ### Use Pathfinder's metric estimate for sampling -To use Pathfinder's metric with no metric adaptation, we need to use Pathfinder's own [`RankUpdateEuclideanMetric`](@ref) type, which just wraps our inverse metric estimate for use with AdvancedHMC. +To use Pathfinder's metric with no metric adaptation, we need to use Pathfinder's own [`RankUpdateEuclideanMetric`](@ref PathfinderAdvancedHMCExt.RankUpdateEuclideanMetric) type, which just wraps our inverse metric estimate for use with AdvancedHMC. We can construct this metric by calling `AdvancedHMC.AbstractMetric`: ```@example 1 diff --git a/docs/src/lib/public.md b/docs/src/lib/public.md index 243c6312..73eb8169 100644 --- a/docs/src/lib/public.md +++ b/docs/src/lib/public.md @@ -27,3 +27,11 @@ Order = [:function, :type] Public = true Private = false ``` + +```@meta +CurrentModule = Base.get_extension(Pathfinder, :PathfinderAdvancedHMCExt) +``` + +```@docs +RankUpdateEuclideanMetric +``` From d99fad37aa8d3c6828faa7a49d481d826c61cc2b Mon Sep 17 00:00:00 2001 From: Seth Axen Date: Tue, 12 Aug 2025 17:11:00 +0200 Subject: [PATCH 8/9] Increment minor version number --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index fb65650f..1931f376 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Pathfinder" uuid = "b1d3bc72-d0e7-4279-b92f-7fa5d6d2d454" authors = ["Seth Axen and contributors"] -version = "0.9.17" +version = "0.10.0-DEV" [deps] ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" From 90f8ec2e5cf46cfe2da296b6bfc900e380204e6d Mon Sep 17 00:00:00 2001 From: Seth Axen Date: Tue, 12 Aug 2025 19:25:22 +0200 Subject: [PATCH 9/9] Specify codecov token for codecov action --- .github/workflows/IntegrationTests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/IntegrationTests.yml b/.github/workflows/IntegrationTests.yml index abdcbff8..69a4c80d 100644 --- a/.github/workflows/IntegrationTests.yml +++ b/.github/workflows/IntegrationTests.yml @@ -44,3 +44,4 @@ jobs: - uses: codecov/codecov-action@v5 with: files: lcov.info + token: ${{ secrets.CODECOV_TOKEN }}