Skip to content

Feature/prior classes#91

Merged
MaartenMarsman merged 43 commits into
mainfrom
feature/prior-classes
Apr 27, 2026
Merged

Feature/prior classes#91
MaartenMarsman merged 43 commits into
mainfrom
feature/prior-classes

Conversation

@MaartenMarsman
Copy link
Copy Markdown
Collaborator

@MaartenMarsman MaartenMarsman commented Apr 9, 2026

...

MaartenMarsman and others added 22 commits April 3, 2026 12:55
…riors

Replace hardcoded Cauchy/beta-prime priors with a BAS-inspired prior class
system. Users now specify priors via constructor functions:

  bgm(x, interaction_prior = normal_prior(0.5),
         threshold_prior = normal_threshold_prior(1),
         edge_prior = beta_bernoulli_prior(2, 5))

R-level changes:
- R/priors.R: 7 prior constructors (cauchy_prior, normal_prior,
  beta_prime_prior, normal_threshold_prior, bernoulli_prior,
  beta_bernoulli_prior, sbm_prior) with print methods and unpackers
- bgm() and bgmCompare(): new interaction_prior, threshold_prior,
  edge_prior object parameters; all old scalar params deprecated via
  lifecycle with full backward compatibility

C++ changes:
- src/priors/interaction_prior.h: InteractionPriorType and
  ThresholdPriorType enums with logp/grad inline functions
- All R::dcauchy() calls replaced with interaction_prior_logp() across
  GGM, OMRF, MixedMRF, and bgmCompare model code (~50 call sites)
- All inline log_beta_prior lambdas replaced with threshold_prior_logp()
- Prior types flow from R -> spec -> C++ bridge -> model constructors

This enables Normal priors for SBC validation studies where Cauchy
priors generate degenerate data, and prepares the architecture for
future g-priors and other prior families.
sample_mixed.cpp checked for "interaction_prior" and "threshold_prior"
keys in the R input list, but run_sampler.R sends them as
"interaction_prior_type" and "threshold_prior_type". This mismatch
caused the mixed model to silently ignore user-specified priors and
always fall back to Cauchy/beta-prime defaults.

Adds test-prior-interface.R with 54 tests covering all prior
constructors × model types (ordinal, GGM, mixed, blume-capel,
bgmCompare), edge selection, backward compatibility, and stored
prior info.
…anup

- Use n-1 effective degrees of freedom in GGM likelihood for centered data,
  fixing systematic overestimation of diagonal precision elements
- Add sample_ggm_prior() NUTS-based prior sampler for SBC validation,
  supporting both full and constrained (sparse) graphs via RATTLE
- Remove redundant Gamma(1,1) diagonal prior from edge parameter and
  edge indicator updates (cancels under constrained Cholesky parameterization)
- Guard initialize_precision_from_mle() against n=0 (prior-only sampling)
- Regenerate RcppExports (remove stale sample_mixed_prior binding)
- Document interaction_prior and threshold_prior params in bgmCompare
…oxygen; update README; fix mixed MRF prior

- Revert posterior_mean_associations back to posterior_mean_pairwise across
  all R code, man pages, and tests for consistency with other output and
  extractor naming conventions.
- Trim detailed roxygen sections in bgm() and bgmCompare() to concise
  summaries with a pointer to the package website.
- Update x parameter documentation to mention continuous variables and
  GGM column-centering.
- Align README citation section with the website.
- Fix mixed MRF interaction prior: evaluate on Kyy = -Omega/2 scale with
  chain-rule correction.
- Update NEWS.md with acceptance rate fix.
- Merge bgms_interaction_prior and bgms_threshold_prior into a single
  bgms_parameter_prior S3 class. All prior families (Cauchy, Normal,
  Beta-Prime) are now valid for interactions, thresholds, and means.
- Constructors use dual class vectors for backward compatibility:
  cauchy_prior/normal_prior inherit bgms_interaction_prior,
  beta_prime_prior inherits bgms_threshold_prior.
- Remove normal_threshold_prior() (never released); use normal_prior().
- Add means_prior argument to bgm() for continuous variable means in
  mixed MRF (currently plumbed to C++ but not yet consumed).
- Add unpack_parameter_prior() as unified unpacker; existing unpack
  functions become thin wrappers.
- Convert test fixtures from deprecated string edge priors to S3 objects.
- Add tests for string edge_prior deprecation warnings and class-based
  edge prior plumbing.
- Apply package-wide styler formatting.
- New bgms_scale_prior S3 class for positive scale parameters
  (precision matrix diagonal).
- gamma_prior(shape, rate) and exponential_prior(rate) constructors.
- New precision_scale_prior argument in bgm() for GGM and mixed MRF.
- Plumbed through bgm_spec and run_sampler to inputFromR (C++ not yet
  consuming the values).
- Add prior constructors section to _pkgdown.yml.
New header src/priors/parameter_prior.h with:
- BaseParameterPrior abstract base class (virtual logp, grad, clone)
- CauchyPrior, NormalPrior, BetaPrimePrior for real-valued parameters
- GammaScalePrior for positive parameters (precision diagonal)
- Factory functions create_parameter_prior() and create_scale_prior()
- All concrete classes marked final for devirtualization in hot loops

Not yet wired into models (Phase 4).
Replace InteractionPriorType enum + pairwise_scale_ with
unique_ptr<BaseParameterPrior> interaction_prior_ and diagonal_prior_
throughout the GGM model:

- ggm_model.h: constructors, copy constructor, member declarations
- ggm_model.cpp: all Metropolis acceptance ratio computations
- ggm_gradient.h/cpp: rebuild() takes prior refs, logp/grad use
  virtual dispatch instead of switch statements
- sample_ggm.cpp: construct priors from inputFromR via factories
- ggm_gradient_interface.cpp: update all test interface functions
- Replace enum + scalar prior params with unique_ptr<BaseParameterPrior>
  for both interaction and threshold priors in OMRF model.
- Add logp(x, scale_factor) and grad(x, scale_factor) virtual methods
  to BaseParameterPrior for OMRF's per-edge pairwise_scaling_factors.
- Override in CauchyPrior and NormalPrior to apply multiplicative scale.
- Update factory function and sample_omrf.cpp to construct priors from
  inputFromR.
Replace enum + scalar prior params with unique_ptr<BaseParameterPrior>
for all four prior roles in the Mixed MRF model:

- interaction_prior_: pairwise interactions (discrete-discrete, etc.)
- threshold_prior_: main effects / thresholds (discrete variables)
- means_prior_: continuous variable means (was hardcoded Normal(0,1))
- diagonal_prior_: precision diagonal (was hardcoded Gamma(1,1))

Updated: mixed_mrf_model.h/cpp (constructors, members, copy),
mixed_mrf_metropolis.cpp (all MH acceptance ratios),
mixed_mrf_gradient.cpp (log-posterior and gradient computations),
sample_mixed.cpp (prior construction from inputFromR),
mixed_gradient_interface.cpp (test interface functions).
Replace enum + scalar prior params with const BaseParameterPrior&
references throughout the bgmCompare subsystem:

- Three prior objects: interaction_prior (baseline pairwise),
  difference_prior (group differences), threshold_prior (main effects)
- Updated all function signatures through the 6-deep call chain
- bgmCompare_interface.cpp constructs priors via factories
- Uses logp(x, scale_factor) for pairwise_scaling_factors
Delete src/priors/interaction_prior.h (InteractionPriorType and
ThresholdPriorType enums, and the free logp/grad functions). All
models now use the polymorphic BaseParameterPrior hierarchy from
parameter_prior.h exclusively.

Remove redundant #include "priors/interaction_prior.h" from all
headers and source files that already include parameter_prior.h.
New test file test-parameter-prior-cpp.R (240 tests) covering:

1. C++ prior logp/grad correctness: each prior class (Cauchy, Normal,
   Beta-Prime, Gamma, Exponential) verified against R reference
   implementations at multiple parameter values.

2. Scaled variant correctness: logp(x, scale_factor) and
   grad(x, scale_factor) verified against reference at scaled
   parameters (used by OMRF/bgmCompare pairwise_scaling_factors).

3. Numerical gradient verification: GGM gradient engine tested with
   Normal, Beta-Prime, and non-default Gamma diagonal priors on both
   full and sparse graphs; analytic gradients match finite differences.
   Both active-theta (NUTS) and full-space (RATTLE) parameterizations.

4. Prior consumption tests: verify that non-default precision_scale_prior
   and means_prior produce different posteriors than defaults, confirming
   the C++ code actually uses the new prior objects.

New C++ test interface: src/prior_test_interface.cpp exposing
test_parameter_prior(), test_scale_prior(), and prior-parameterized
gradient test functions.
Extend mixed_test_logp_and_gradient and mixed_test_logp_and_gradient_full
C++ test interfaces to accept means_prior and diagonal_prior parameters
(previously hardcoded as Normal(0,1) and Gamma(1,1)).

Add three mixed MRF numerical gradient tests:
- Normal interaction prior
- Cauchy means prior + Gamma(2,1) diagonal prior
- All non-default priors (Normal interaction, Normal threshold,
  Cauchy means, Gamma(0.5,2) diagonal)

All analytic gradients match finite differences to < 1e-4.
Verify that edge selection (spike-and-slab) works correctly when
combined with non-default priors across all model types:

- GGM: normal_prior, beta_prime_prior, non-default diagonal prior
- OMRF: normal_prior interaction + cauchy threshold,
        beta_prime_prior interaction
- Mixed MRF: all four non-default priors simultaneously

All tests verify inclusion indicators are in [0,1] and the sampler
runs without error.
Verify bgmCompare runs correctly with:
- normal_prior interaction + cauchy threshold (no selection)
- beta_prime_prior interaction + beta_prime_prior threshold (no selection)
- normal_prior for both + difference selection enabled
Rename the edge prior class to bgms_indicator_prior since the same
selection prior structure (Bernoulli, Beta-Bernoulli, SBM) applies to
both edge inclusion in bgm() and difference selection in bgmCompare().

- Rename class, print method, and unpack function throughout
- bgmCompare() now accepts indicator prior objects for difference_prior
  (bernoulli_prior, beta_bernoulli_prior, sbm_prior)
- Deprecate string-valued difference_prior and loose difference_probability
- Convert test fixture from deprecated string to prior object
- SBM prior is now available for difference selection in bgmCompare
Replace <U+201C>/<U+201D> (smart quotes), <U+2013> (en-dash),
<U+2014> (em-dash), and <U+2019> (smart apostrophe) with ASCII
equivalents across all R source files. These were introduced by
styler converting actual Unicode characters to escape sequences.
Rename roxygen titles and descriptions from "Edge Inclusion" to
"Inclusion Indicators" for bernoulli_prior, beta_bernoulli_prior,
and sbm_prior. These priors apply to both edge selection in bgm()
and difference selection in bgmCompare().
- Replace <U+2192> (arrow) and <U+00D7> (multiplication) escape
  sequences with ASCII -> and x in comments.
- Add explicit error when edge_prior receives a non-indicator,
  non-string object (e.g. cauchy_prior), instead of falling through
  to an unhelpful match.arg error. String values are still accepted
  via the deprecated legacy path.
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 9, 2026

Codecov Report

❌ Patch coverage is 80.04032% with 198 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.95%. Comparing base (e32cb61) to head (d4bc427).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
R/priors.R 68.93% 64 Missing ⚠️
R/bgmCompare.R 35.08% 37 Missing ⚠️
src/mixed_gradient_interface.cpp 40.00% 30 Missing ⚠️
R/bgm.R 75.67% 18 Missing ⚠️
src/models/mixed/mixed_mrf_metropolis.cpp 36.36% 14 Missing ⚠️
src/bgmCompare/bgmCompare_logp_and_grad.cpp 69.23% 8 Missing ⚠️
src/models/omrf/omrf_model.cpp 70.37% 8 Missing ⚠️
src/models/ggm/ggm_model.cpp 64.70% 6 Missing ⚠️
R/bgm_spec.R 97.63% 3 Missing ⚠️
R/sample_precision_prior.R 94.73% 3 Missing ⚠️
... and 3 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #91      +/-   ##
==========================================
- Coverage   87.14%   86.95%   -0.19%     
==========================================
  Files          72       76       +4     
  Lines       12291    12929     +638     
==========================================
+ Hits        10711    11243     +532     
- Misses       1580     1686     +106     

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

Comment thread src/models/ggm/ggm_gradient.cpp
Brings in the pd-fix for random graph initialization and the JASP
progress_callback plumbing. Conflicts were textual only: the deprecated
prior arguments added on feature branch sat in the same argument lists
where main added progress_callback; both sides preserved. Unicode-escape
conflicts in bgm.R / test_compliance.R were already resolved on feature
branch (commits f457435, 14fe873).
The top-level trajectory loop in nuts_step overwrote the Metropolis
contribution (alpha, n_alpha) with the latest subtree's values each
iteration instead of accumulating across the full trajectory. The
reported accept_prob therefore reflected only the last built subtree,
biasing the signal consumed by dual-averaging step-size adaptation.

Match Stan's base_nuts.hpp semantics: accumulate sum_metro_prob and
n_leapfrog across every subtree built (including ones that terminated
early), outside the s_prime == 1 guard, since every leapfrog step
contributes to the Metropolis diagnostic.
Adds the Claude Code settings directory to .Rbuildignore so it is not
flagged as an unexpected hidden directory by --as-cran checks. The
directory is also listed in .gitignore but R CMD check scans the
working tree, not the git index.
Surface the per-iteration mean Metropolis acceptance probability in
fit$nuts_diag$accept_prob (chains x iterations), paralleling Stan's
accept_stat__ output. Adds a per-chain mean_accept_prob summary and
threads the value through the bgm and bgmCompare output pipelines.

The new field also serves as a direct regression guard for the
accept_prob accumulation bug fixed previously: the test in
test-reversibility-check.R asserts a well-tuned GGM produces mean
accept_prob above the dual-averaging target.
MaartenMarsman and others added 15 commits April 18, 2026 00:09
The 'Geweke-style forward-sampling test' added in #86 was never a valid
Geweke joint distribution test: it drew K from a Wishart(p+1, I) prior
while bgms targets a Cauchy(0, 2.5) + Gamma(1, 1) prior, ran 50 warmup
iterations (so the kernel kept changing during 'one transition'), and
started NUTS from a data-driven init. A bug-free sampler could not
satisfy the equality it was asserting; the test has been quietly
failing on every nightly run since it was introduced.

The NUTS-vs-MH moment comparison and the SBC test cover the same
correctness territory properly. A future commit will add a proper SBC
replacement (TODO noted in the file header).
The nightly workflow invoked 'devtools::test()', which returns a
testthat result object with exit code 0 even when tests fail. As a
result the job reported 'success' on every nightly run despite
testthat printing 'FAIL 4' (the Geweke test, now removed).

Switch to 'devtools::test(stop_on_failure = TRUE)' so a single test
failure propagates to the job status and the nightly turns red.
Replace the Hoffman-Gelman slice sampler inside nuts_step with Stan's
multinomial variant. Candidates are now weighted by log w_i = H0 - h_i
(the Hamiltonian offset of each leaf from the initial state) and
combined with log-sum-exp in log space:

  - Base case: log_sum_weight = H0 - h (or -inf on divergence); the
    non-reversible early return runs BEFORE logp evaluation, so broken
    states never hit the posterior cache.
  - Sibling subtrees (within build_tree) are combined with symmetric
    multinomial sampling: accept the final subtree with probability
    exp(w_final - log_sum_exp(w_init, w_final)).
  - Top-level (in nuts_step) uses biased progressive sampling:
    accept the new subtree with probability min(1, w_subtree / w_traj),
    so later subtrees are preferred on average.
  - Divergence is detected by (h - H0) > Delta_max (= 1000), matching
    Stan; no slice variable is needed.

The Metropolis diagnostic (alpha and n_leapfrog) is computed for every
leaf regardless of divergence or reversibility and accumulated outside
the s_prime guard, so the reported accept_prob still reflects the full
trajectory.

Drops the vestigial theta_0 and r0 parameters from build_tree's
signature. Adds a numerically stable log_sum_exp helper under src/math/.
n_alpha is renamed to n_leapfrog and n_prime is replaced by
log_sum_weight in BuildTreeResult, matching Stan's vocabulary.

Validation:
  - Full testthat suite green (7362 pass / 43 expected skips).
  - test-ggm-nuts.R (slow) passes including NUTS-vs-MH moment agreement,
    edge-selection accuracy, gradient-near-PD-boundary, and diagnostics.
  - test-rattle-edge-selection.R (slow) passes.
  - test-mixed-nuts.R (slow) passes.
  - test-sbc-ggm.R NUTS part passes; pre-existing MH SBC failure is
    unaffected by this change.
  - Step 0 regression test (accept_prob >= 0.75 on a well-tuned GGM)
    still passes; mean accept_prob ~ 0.94.
  - Mean tree depth: 2.9100 (pre-swap slice) -> 3.0025 (multinomial),
    within MC noise. Divergence rate unchanged at 0.

References:
  Betancourt, M. (2017). A Conceptual Introduction to Hamiltonian
    Monte Carlo, section A.3.2. arXiv:1701.02434.
  Stan Development Team. base_nuts.hpp.
    https://github.com/stan-dev/stan/blob/develop/src/stan/mcmc/hmc/nuts/base_nuts.hpp
bgms's doubling-window loop produced one extra small trailing window
at the end of Stage-2 whenever warmup \geq 1000. Each window boundary
triggers a mass-matrix update and a step-size reinit (heuristic +
dual-averaging restart), so the spurious extra update disrupted
step-size convergence during the most important part of warmup.

For warmup=1000 the window boundaries now match Stan exactly:
  bgms (before): 100, 150, 250, 450, 850, 950   (6 windows)
  bgms (after):  100, 150, 250, 450, 950        (5 windows, same as Stan)

The rule: when the window AFTER the next would overshoot stage3a_start,
stretch the current next_end to stage3a_start instead of emitting a
smaller trailing window. Matches Stan's
windowed_adaptation::compute_next_window().

Measured improvement at matched settings (3-seed average):
  p=5 tridiagonal GGM, warmup=1000, iter=2000:
    ESS_MIN 2841 -> 3121 (+10%)
    ESS/leapfrog 0.181 -> 0.200
  2D standard normal, warmup=1000, iter=4000:
    ESS_MIN 3306 -> 3466 (+5%)

This is a partial close of the ~30% ESS gap versus Stan; the remaining
gap is still under investigation (step-size reinit heuristic, build-tree
early-return bookkeeping).
The outer trajectory loop in nuts_step was tracking the four U-turn
boundary momenta (p_bck_bck / p_bck_fwd / p_fwd_bck / p_fwd_fwd and
their sharp counterparts) incorrectly:

1. Neither outer-end momentum (p_bck_bck for the leftmost end, p_fwd_fwd
   for the rightmost) was maintained at all. Stan requires them so that
   the 'save old outer end as new interior boundary' step can run
   before each extension.

2. The backward branch assigned the subtree's BEG fields to the
   'bck_bck' slot and the subtree's END fields to the 'bck_fwd' slot,
   which is the opposite of what the names mean. For a backward
   subtree, result.p_beg is the FIRST leaf (interior right, closest to
   the rest of the trajectory) and result.p_end is the LAST leaf
   (outer leftmost). The forward branch was correct; only the backward
   branch had the asymmetry.

3. Neither branch saved the old outer end into the interior-boundary
   slot before calling build_tree, so the extended U-turn checks
   (checks 2 and 3) used stale momenta from whatever extension last
   updated those variables — typically the initial r0 when the
   sampler happened to extend in the same direction multiple times
   in a row.

The combined effect: on targets where the trajectory's U-turn
geometry depends on the interior boundary (the higher the dimension
or the more non-isotropic the posterior, the stronger the effect),
bgms terminated trees at positions Stan would have continued past.
Trajectories were cut short, ESS was lost.

Fix: (1) declare p_bck_bck and p_fwd_fwd in nuts_step and keep them
updated; (2) save p_bck_bck -> p_fwd_bck before each backward
extension and p_fwd_fwd -> p_bck_fwd before each forward extension,
matching Stan's base_nuts.hpp; (3) normalize the backward-branch
post-call assignments so p_bck_bck holds the outer-leftmost momentum
(result.p_end) and p_bck_fwd holds the interior-right momentum
(result.p_beg).

Validation:
  - 6 targets x 5 seeds (gauss_2d, ggm_p3/p5/p8/p12/p20): ESS_min up
    on 6/6 targets, ranging +1.3% (p=8) to +95.1% (p=20). Treedepth
    increases slightly (trees now run to real U-turns instead of
    premature ones) but ESS/leapfrog also improves on 5/6.
  - Posterior mean/sd differences <= 0.003 across all targets; sd
    ratios in [0.97, 1.01]. Same target, same posterior.
  - Zero divergences in every run.
  - Full testthat suite: 7362/7362 fast tests pass; slow suite shows
    zero new regressions (3 failing tests are pre-existing on HEAD,
    unrelated to NUTS).
  - External 65-D marginal-PL benchmark reports bgms/Stan ESS ratio
    of 1.05 (up from 0.69) at matched settings; posterior-mean /
    sd-ratio agreement preserved.

References:
  Betancourt, M. (2017). A Conceptual Introduction to Hamiltonian
    Monte Carlo. arXiv:1701.02434.
  Stan Development Team. base_nuts.hpp. Verbatim reference checked in
    under dev/stan_reference/.
Three changes, all verified by analytic tests and paired SBC against
the mixedGM Stan reference.

1. Interaction prior on Kyy scale (pure GGM + mixed MRF continuous
   block). The `interaction_prior` now refers to off-diagonal entries
   on the K_yy = -K/2 association scale, matching the mixed-MRF
   convention. A `Normal(0, scale)` prior therefore constrains K_yy
   off-diagonals with standard deviation `scale`, equivalent to
   Normal(0, 2*scale) on the precision entries.

2. Mixed-MRF marginal pseudo-likelihood
   (`pseudolikelihood = "marginal"`): the off-diagonal cross-induced
   contribution to the effective interaction matrix
   M = A_xx + 2 A_xy Sigma_yy A_xy' was under-counted by a factor of 2
   in the rest-score computation. Forward log-posterior and analytic
   gradient now match a direct Gaussian-integral reference and central
   finite differences to machine precision. The fix affects both the
   NUTS and adaptive-Metropolis paths.

3. NUTS Stage-2 warmup windowing: when the window after the next would
   overshoot the Stage-3a boundary, the current next window is now
   stretched to absorb the remaining Stage-2 budget instead of
   emitting a small trailing window. Each window boundary triggers a
   mass-matrix update and step-size reinitialization, so eliminating
   the disruptive trailing window improves dual-averaging convergence
   and matches Stan's windowed_adaptation::compute_next_window.
The user-facing wrapper now validates inputs, rejects beta_prime_prior()
with a clear message, passes the scale_prior_type through to C++ via
create_scale_prior(), and wires verbose to the progress manager. The
return list is fully documented with examples.

Adds tests/testthat/test-sample-ggm-prior.R covering return shape,
edge_indicators constraint enforcement (algebraic vs RATTLE-projected
zeros), interaction- and scale-prior plumbing, and error paths.
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).
Styler pass via inst/styler/bgms_style.R picked up the assignment-style
violations introduced when keeping HEAD's prior-class additions in
R/bgm.R, R/bgm_spec.R, R/run_sampler.R, R/sample_ggm_prior.R, and
the auto-merged R/bgmCompare.R / tests/.
Both the CRAN release of easybgm and its in-development rewrite are
stamped 0.4.0, so the previous version-based threshold
(version < 0.4.0) returned FALSE for both, sending an S7 fit to
old-API code that does class(fit) <- ... and fit$arguments$... and
crashing it.

Replace the version check with a source-code fingerprint: probe
the easybgm namespace for bgm_extract.package_bgms and inspect
its body for extract_category_thresholds (renamed to
extract_main_effects in bgms 0.2.0). The CRAN body still calls the
old name; the rewrite uses extract_main_effects.

Verified:
- easybgm CRAN main (0.4.0, old code):    182 pass, 0 fail
  (was 87 pass + 3 errors under the version-only threshold)
- easybgm update_easybgm (0.4.0, new):    232 pass, 0 fail
Source-fingerprint detection was a workaround for the version
collision between CRAN main and the in-development rewrite (both
0.4.0). Once update_easybgm bumps to 0.5.0, the version-based
threshold is the cleaner discriminator.

Status under the 0.5.0 threshold:
- CRAN main 0.4.0:       shim -> S3 list (still 182 pass)
- update_easybgm 0.4.0:  shim -> S3 list (still 232 pass; the
  new extractor API works on S3 too, so this is fine until the
  version is bumped to 0.5.0)
- update_easybgm >= 0.5.0 (after bump): S7 path
The previous name was opaque: the function samples precision matrices
$K$ from the GGM prior (n=0, S=0 makes the likelihood flat), so
'precision_prior' captures both *what* it draws and *where* it draws
from. Also list it under "Simulation and prediction" in
_pkgdown.yml — its absence was breaking the GitHub Pages build.

Renamed:
- R/sample_ggm_prior.R          -> R/sample_precision_prior.R
- tests/testthat/test-sample-ggm-prior.R -> test-sample-precision-prior.R
- C++ entry point sample_ggm_prior() -> sample_precision_prior()
- Rcpp export name sample_ggm_prior_cpp -> sample_precision_prior_cpp

Tests: 6663/6732 pass, 0 fail, 0 error.
simulate_* = forward-generate data given known parameters (cheap, exact).
sample_*   = MCMC draws from a target distribution (NUTS/Metropolis).

The two prefixes coexist on purpose; record that under the
'Simulation and prediction' section description so users browsing
the reference don't read it as accidental inconsistency.
@MaartenMarsman MaartenMarsman marked this pull request as ready for review April 27, 2026 10:41
@MaartenMarsman MaartenMarsman merged commit 586df5f into main Apr 27, 2026
8 of 10 checks passed
@MaartenMarsman MaartenMarsman deleted the feature/prior-classes branch April 27, 2026 10:44
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.

2 participants