Skip to content

NUTS: the No-U-Turn Sampler (self-tuning trajectory length) - #56

Merged
davidkhjo merged 3 commits into
mainfrom
nuts-sampler
Aug 21, 2026
Merged

NUTS: the No-U-Turn Sampler (self-tuning trajectory length)#56
davidkhjo merged 3 commits into
mainfrom
nuts-sampler

Conversation

@davidkhjo

Copy link
Copy Markdown
Owner

NUTS — the last item on the roadmap. HMC that tunes both of its knobs away.

What

  • Multinomial NUTS (Hoffman & Gelman 2014): each draw doubles its trajectory until the path makes a whole-span U-turn, so there is no leapfrog_steps to set; and a dual-averaging warmup tunes the step size to target_accept (default 0.8), so there is no step-size sweep. Unbiased — targets exactly p ∝ exp(-E).
  • Batched via lockstep-with-freeze: all B chains build their trees to a shared depth each doubling, but a chain that has stopped (U-turn or divergence) is frozen — every state write is gated by a per-chain active mask (torch.where). This yields, per chain, exactly the draw an independent single-chain NUTS would produce (no cross-chain coupling; a stopped chain's state is never rewritten). Wasted leapfrogs on finished chains are the only cost.
  • Numerically careful: log-space multinomial weights (logaddexp) for progressive sampling; non-finite / ΔH > max_delta_h treated as divergence (weight 0, chain frozen) so a NaN can't leak across chains; trajectory math stays off-graph and the proposal is detached. Reuses HMC's leapfrog, _energy_grad, and AdaptiveMALA's dual-averaging recursion.
  • Exposes last_tree_depth and a divergences count for diagnostics.

Validation (closed-form / distributional)

  • Recovers a standard and a correlated Gaussian's covariance; tunes to 0.8 acceptance with zero divergences on the Gaussian.
  • Enters Neal's funnel (finite, spreads — with the honest caveat that an identity metric under-samples the neck).
  • Terminates by U-turn: on an easy Gaussian the tree depth stays small ({1,2,3}), never bottoming out at max_depth.

Notes

  • Example examples/nuts_sampling.py (funnel + per-draw tree-depth histogram). torch-only; public API preserved; accumulates under the unreleased 0.16.0.
  • This completes the roadmap end to end — no deferred features remain.

🤖 Generated with Claude Code

davidkhjo and others added 3 commits August 21, 2026 13:31
Multinomial NUTS (Hoffman & Gelman 2014) with dual-averaging step-size warmup:
HMC that doubles each trajectory until a whole-span U-turn and tunes epsilon to
target_accept, so it needs neither leapfrog_steps nor a step-size sweep. All B
chains run in lockstep with a per-chain freeze mask (every state write gated by an
active bool), so each chain's draw is identical to independent single-chain NUTS.
Log-space multinomial weights keep the progressive sampling numerically stable;
divergence and tree-depth are exposed as diagnostics.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Recovers a standard and a correlated Gaussian's covariance (pooling late
near-independent draws), tunes to 0.8 acceptance with zero divergences on the
Gaussian, enters Neal's funnel (finite, loose v.std band), and terminates by
U-turn at small tree depths rather than bottoming out at max_depth. Plus the
accept-rate lifecycle and constructor validation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Example runs NUTS on Neal's funnel and plots the per-draw tree-depth distribution
(trajectory length adapts; it doesn't bottom out at max_depth), printing tuned
step size, acceptance, and divergences. README samplers row + examples list and
the unreleased 0.16.0 CHANGELOG updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@davidkhjo
davidkhjo merged commit 69aa320 into main Aug 21, 2026
5 checks passed
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.

1 participant