Skip to content

Fix #281: Fix sampler failure when n_samples = 1#489

Draft
nsiccha wants to merge 1 commit intomainfrom
issue-281-n-samples-1
Draft

Fix #281: Fix sampler failure when n_samples = 1#489
nsiccha wants to merge 1 commit intomainfrom
issue-281-n-samples-1

Conversation

@nsiccha
Copy link
Copy Markdown
Contributor

@nsiccha nsiccha commented Mar 19, 2026

I'll check the changes before marking it as ready for review.

Human content above


Claude content below

Fix sampler failure when n_samples = 1

Problem

Calling sample(h, κ, θ, 1) crashes in the verbose end-of-sampling report. The EBFMI function (src/diagnosis.jl) computes:

mean(i -> (Es[i + 1] - Es[i]) .^ 2, 1:(length(Es) - 1)) ./ var(Es)

With 1 sample, length(Es) = 1, so it evaluates mean(f, 1:0) — iterating over an empty range. Julia's Statistics.mean over an empty collection throws an error.

MWE

See 281-n-samples-1.jl. Calls sample(h, κ, θ, 1; verbose=true) and checks that it completes without error. Fails on main with ArgumentError: mean of empty collection inside the EBFMI computation.

Change

2 files changed:

  • src/sampler.jl — move EBFMI_est computation inside the if θ isa AbstractVector / else branches; guard with length(stats) > 1 ? EBFMI(...) : NaN
  • test/sampler.jl — add @testset "n_samples=1 does not crash" that calls sample with n_samples=1, verbose=true and asserts the result has length 1

Notes

  • verbose=true by default, so this crash affects all users calling sample(h, κ, θ, 1) without explicitly passing verbose=false
  • n_adapts defaults to min(div(1, 10), 1000) = 0, so adaptation is correctly skipped — the only broken part was the end-of-sampling log
  • EBFMI requires at least 2 consecutive energy values to be meaningful; NaN is the correct sentinel for undefined

MWE

281-n-samples-1.jl

# MWE for https://github.com/TuringLang/AdvancedHMC.jl/issues/281
# Fails on main (ArgumentError: mean of empty collection in EBFMI),
# exits 0 after fix.

using AdvancedHMC, LinearAlgebra, Random

D   = 2
ℓπ(θ)    = -sum(abs2, θ) / 2
∂ℓπ∂θ(θ) = (ℓπ(θ), -θ)

h = Hamiltonian(DiagEuclideanMetric(D), ℓπ, ∂ℓπ∂θ)
κ = HMCKernel(Trajectory{MultinomialTS}(Leapfrog(0.1), GeneralisedNoUTurn()))

# verbose=true is the default and triggers EBFMI computation
try
    samples, stats = sample(h, κ, randn(MersenneTwister(42), D), 1; verbose=true, progress=false)
    length(samples) == 1 || (println("Wrong number of samples"); exit(1))
    length(stats)   == 1 || (println("Wrong number of stats");   exit(1))
catch e
    @error "sample with n_samples=1 threw an error" exception=e
    exit(1)
end

main output:

# MWE: 281-n-samples-1.jl on main
# started: 2026-03-19 20:01:32
# dir: /home/niko/github/issues/AdvancedHMC.jl
---
==> Pkg.instantiate()
==> Running 281-n-samples-1.jl
┌ Error: sample with n_samples=1 threw an error
│   exception = MethodError: reducing over an empty collection is not allowed; consider supplying `init` to the reducer
└ @ Main ~/github/issues/AdvancedHMC/proposals/281-n-samples-1.jl:20

# exit_code: 1
# status: FAIL
# finished: 2026-03-19 20:02:02

worktree output:

# MWE: 281-n-samples-1.jl on worktree
# started: 2026-03-19 20:01:32
# dir: /home/niko/github/issues/AdvancedHMC/worktrees/issue-281-n-samples-1
---
==> Pkg.instantiate()
Precompiling packages...
    AdvancedHMC Being precompiled by another process (pid: 2096748, pidfile: /home/niko/.julia/compiled/v1.10/AdvancedHMC/WaglY_80WTF.ji.pidfile)
  32286.5 ms  ✓ AdvancedHMC
  1 dependency successfully precompiled in 38 seconds. 69 already precompiled.
==> Running 281-n-samples-1.jl
┌ Info: Finished 1 sampling steps for 1 chains in 5.0211e-5 (s)
│   h = Hamiltonian with DiagEuclideanMetric and GaussianKinetic
│   κ = HMCKernel{AdvancedHMC.FullMomentumRefreshment, Trajectory{MultinomialTS, Leapfrog{Float64}, GeneralisedNoUTurn{Float64}}}(AdvancedHMC.FullMomentumRefreshment(), Trajectory{MultinomialTS} with Leapfrog with step size ϵ=0.1 and termination criterion GeneralisedNoUTurn{Float64}(10, 1000.0))
│   EBFMI_est = NaN
└   average_acceptance_rate = 0.9991638522641156

# exit_code: 0
# status: PASS
# finished: 2026-03-19 20:02:27

Fixes #281

sample() with n_samples=1 crashed in the verbose end-of-sampling report
because EBFMI() called mean() over an empty range. Guard with a
length(stats) > 1 check and return NaN when undefined. Add regression test.
average_acceptance_rate = mean(map(s -> s.acceptance_rate, stats))
if θ isa AbstractVector
n_chains = 1
EBFMI_est = length(stats) > 1 ? EBFMI(map(s -> s.hamiltonian_energy, stats)) : NaN
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
EBFMI_est = length(stats) > 1 ? EBFMI(map(s -> s.hamiltonian_energy, stats)) : NaN
EBFMI_est =
length(stats) > 1 ? EBFMI(map(s -> s.hamiltonian_energy, stats)) : NaN

EBFMI_est = length(stats) > 1 ? EBFMI(map(s -> s.hamiltonian_energy, stats)) : NaN
else
n_chains = size(θ, 2)
EBFMI_est = length(stats) > 1 ? EBFMI(map(s -> s.hamiltonian_energy, stats)) : fill(NaN, n_chains)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
EBFMI_est = length(stats) > 1 ? EBFMI(map(s -> s.hamiltonian_energy, stats)) : fill(NaN, n_chains)
EBFMI_est = if length(stats) > 1
EBFMI(map(s -> s.hamiltonian_energy, stats))
else
fill(NaN, n_chains)
end

@github-actions
Copy link
Copy Markdown
Contributor

AdvancedHMC.jl documentation for PR #489 is available at:
https://TuringLang.github.io/AdvancedHMC.jl/previews/PR489/

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 19, 2026

Codecov Report

❌ Patch coverage is 50.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 78.04%. Comparing base (6bc0c74) to head (1a92eef).

Files with missing lines Patch % Lines
src/sampler.jl 50.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #489      +/-   ##
==========================================
+ Coverage   77.71%   78.04%   +0.33%     
==========================================
  Files          21       21              
  Lines        1270     1271       +1     
==========================================
+ Hits          987      992       +5     
+ Misses        283      279       -4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@nsiccha nsiccha changed the title Fix #281: guard EBFMI computation when n_samples=1 Fix #281: Fix sampler failure when n_samples = 1 Mar 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sampler failure when num of samples = 1

1 participant