Skip to content

Chore/sampler rename and collapse#95

Merged
MaartenMarsman merged 6 commits into
mainfrom
chore/sampler-rename-and-collapse
Apr 26, 2026
Merged

Chore/sampler rename and collapse#95
MaartenMarsman merged 6 commits into
mainfrom
chore/sampler-rename-and-collapse

Conversation

@MaartenMarsman
Copy link
Copy Markdown
Collaborator

Summary

Two-commit cleanup of the sampler hierarchy after pure HMC removal:

  1. Rename passHMCAdaptationControllerNUTSAdaptationController, hmc_adaptation.hnuts_adaptation.h, hmc_adaptnuts_adapt, comment cleanup of "HMC/NUTS" co-mentions in sampler/model headers. Algorithm-level mentions (mcmc/algorithms/hmc.h, leapfrog.h) preserved — those describe Hamiltonian dynamics that NUTS still uses.
  2. Collapse passGradientSamplerBase is now empty (single descendant after HMC removal); folded its scaffolding directly into NUTSSampler::step() / initialize(). The do_gradient_step() virtual hook goes away.

New hierarchy:
SamplerBase
├── MetropolisSampler (forwards to model.do_one_metropolis_step)
└── NUTSSampler (gradient scaffolding + leapfrog/RATTLE)

No symmetric do_step() hook — MetropolisSampler has nothing to scaffold, and the NUTS adaptation controller's per-sampler ownership is principled (asymmetric with the model-side MetropolisAdaptationControllers on purpose). Rationale captured in dev/plans/backlog/post-hmc-sampler-cleanup.md.

Test plan

  • roxygen2::roxygenise() — no-op
  • Rcpp::compileAttributes() — no-op
  • styler::style_pkg() idempotent
  • lintr::lint_package() — no lints
  • Clean rebuild: passes
  • devtools::test() → 6272 PASS / 0 FAIL / 68 SKIP
  • Pure restructure — no behavior change.

Pure HMC with a fixed trajectory length is superseded by NUTS, which
adapts trajectory length and is more reliable on edge-selected GGMs
(where pure HMC's RATTLE integration is fragile). Both arguments were
already deprecated; this removes them entirely along with the supporting
machinery.

Removed:
- src/mcmc/samplers/hmc_sampler.h (HMCSampler class)
- update_hmc_bgmcompare() in src/bgmCompare/bgmCompare_sampler.cpp
- hamiltonian_mc enum value and string-parser branch
- num_leapfrogs field on SamplerConfig and dead pass-through in
  sample_omrf / sample_mixed_mrf entry points
- hmc_num_leapfrogs argument throughout the R API and bgmCompare's
  C++ Rcpp interface

Kept (NUTS continues to use them):
- src/mcmc/algorithms/{hmc,leapfrog}.* (Hamiltonian / leapfrog / RATTLE
  primitives)
- src/mcmc/samplers/hmc_adaptation.h (step-size + mass-matrix controller)

User-facing impact: bgm()/bgmCompare() with update_method = "hamiltonian-mc"
or hmc_num_leapfrogs = ... now error out (match.arg / unused argument).
NEWS.md updated. HMC compliance fixtures and the test-hmc-ggm.R suite
deleted; helper-fixtures.R no longer exposes get_bgms_fit_hmc().

All 6272 tests pass. Smoke tests confirm clean rejection of removed args.
The marginal pseudo-likelihood (which integrates out the continuous block
when computing discrete full conditionals) is the principled default for
mixed MRF models. The conditional pseudo-likelihood — which conditioned on
observed continuous values — was a legacy approximation that the recent
fix to the mixed-MRF marginal PL target (commit 6853774) made obsolete.
This removes the dual-mode plumbing entirely; marginal is now the only mode.

Removed:
- MixedMRFModel constructor parameter `pseudolikelihood` and the
  `use_marginal_pl_` member, plus the conditional initializer
- ~13 dual-mode branches in mixed_mrf_metropolis.cpp (collapsed to marginal)
- ~19 dual-mode branches in mixed_mrf_gradient.cpp (collapsed to marginal)
- log_conditional_omrf() — no callers remained after the collapse
- pseudolikelihood argument from R API (bgm, bgm_spec) and from C++
  Rcpp interfaces (sample_mixed_mrf, mixed_test_logp_and_gradient[_full],
  mixed_test_project_position, mixed_test_project_momentum,
  mixed_test_leapfrog_constrained)
- pseudolikelihood from tests (test-mixed-nuts, test-mixed-gradient,
  test-mixed-rattle, test-mixed-leapfrog, test-scaling-diagnostics,
  test-validation-slow); the conditional-vs-marginal comparison test was
  deleted (no longer meaningful)

Kept (still used elsewhere or describe single-node densities):
- log_marginal_omrf() — now the only OMRF likelihood path
- log_conditional_ggm() — used by all GGM-related updates regardless of mode
- recompute_marginal_interactions() — now called unconditionally
- marginal_interactions_ member — now always allocated

User-facing impact: bgm() with pseudolikelihood = "..." now errors with
"unused argument". Mixed-MRF fits previously requesting "conditional" will
now silently use marginal — semantically a more correct default but a
behavior change for any caller relying on the conditional approximation.
NEWS.md updated.

All 6272 tests pass. Smoke tests confirm the removed argument is rejected
and that NUTS / adaptive-metropolis on mixed-MRF still produce finite output.
After pure HMC removal, the warmup adaptation controller is used only by
NUTS. Rename it to match.

- src/mcmc/samplers/hmc_adaptation.h → nuts_adaptation.h
- HMCAdaptationController → NUTSAdaptationController
- hmc_adapt → nuts_adapt at all call sites (bgmCompare's NUTS path)
- Replace "HMC/NUTS" / "NUTS/HMC" / "HMC and NUTS" mentions with "NUTS"
  in sampler/model headers and comments. Algorithm-level mentions in
  src/mcmc/algorithms/{hmc,leapfrog}.h are preserved — those describe
  the underlying Hamiltonian dynamics that NUTS still uses.

No behavior change; renames only.
GradientSamplerBase was originally introduced to share warmup adaptation
between HMCSampler and NUTSSampler. With pure HMC removed, NUTS is the
only descendant. The intermediate base class is dead weight: it adds an
inheritance layer with no payoff and uses misleading naming (the "shared
base for gradient-based MCMC" now serves a single sampler).

This commit folds the gradient scaffolding directly into NUTSSampler:

- step() now contains the Stage-3c restart, mass-matrix update orchestration,
  step-size heuristic re-run, and the leapfrog/RATTLE call as one body.
- initialize() / do_initialize() and the NUTSAdaptationController member
  (renamed nuts_adapt_) move into NUTSSampler as private members.
- The protected do_gradient_step() virtual hook goes away; NUTSSampler
  dispatches to do_unconstrained_step() / do_constrained_step() inline.

Hierarchy is now flat:
  SamplerBase  (abstract: step, initialize, has_nuts_diagnostics)
  ├── MetropolisSampler   (forwards to model.do_one_metropolis_step)
  └── NUTSSampler         (gradient scaffolding + leapfrog/RATTLE)

If a second gradient sampler returns later, re-introducing the base class
is mechanical. Per the design notes in
dev/plans/backlog/post-hmc-sampler-cleanup.md, no symmetric do_step() hook
is added: MetropolisSampler has nothing to scaffold, and the NUTS
adaptation controller's per-sampler ownership is principled (not symmetric
with the model-side MetropolisAdaptationControllers).

src/models/base_model.h doc comments updated: "Used by GradientSamplerBase"
→ "Used by NUTSSampler".

No behavior change; restructure only. All 6272 tests pass.
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 26, 2026

Codecov Report

❌ Patch coverage is 93.40659% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.05%. Comparing base (e19100d) to head (9c1b0af).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/mcmc/samplers/nuts_sampler.h 93.02% 6 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #95      +/-   ##
==========================================
- Coverage   87.17%   87.05%   -0.12%     
==========================================
  Files          71       71              
  Lines       12255    12252       -3     
==========================================
- Hits        10683    10666      -17     
- Misses       1572     1586      +14     

☔ 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.

@MaartenMarsman MaartenMarsman marked this pull request as ready for review April 26, 2026 21:57
@MaartenMarsman MaartenMarsman merged commit d8c0f1d into main Apr 26, 2026
9 of 10 checks passed
@MaartenMarsman MaartenMarsman deleted the chore/sampler-rename-and-collapse branch April 26, 2026 23:24
MaartenMarsman added a commit that referenced this pull request Apr 27, 2026
Brings the HMC removal (PR #93), conditional pseudolikelihood removal
(PR #94), sampler rename/collapse (PR #95), NUTS Stan-compliance fixes
(PR #96), and marginal-PL correctness fixes (PR #97) into the
prior-classes branch.

Conflict resolution rule:
- HMC code → take main's deletion (drops update_hmc_bgmcompare,
  hamiltonian_mc enum branches, hmc_num_leapfrogs args, .Deprecated
  paths, HMC test fixtures)
- if(use_marginal_pl_) { marginal } else { conditional } → keep marginal
  branch only; drop the use_marginal_pl_ field and pseudolikelihood
  string parameter from MixedMRFModel constructor and downstream
  test interfaces
- Prior-class additions (interaction_prior_, threshold_prior_,
  means_prior_, diagonal_prior_) preserved everywhere

Test helper updated to inject the prior-class C++ test functions
(test_parameter_prior, test_scale_prior, ggm_test_logp_and_gradient_prior,
ggm_test_logp_and_gradient_full_prior, ggm_test_leapfrog_constrained_checked,
unpack_interaction_prior, unpack_threshold_prior) into globalenv when
running outside R CMD check.

test-mixed-mrf-likelihood.R reverted to main's version (the
marginal-vs-conditional comparison test no longer applies after
conditional PL removal).

6663 / 6732 tests pass, 0 fail, 0 error, 69 skip (slow/CRAN-gated).
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