feat: determinant-tilt prior on the continuous-precision block#106
Merged
Conversation
Adds a non-negative tilt parameter delta to the GGM gradient engine: multiplies the prior by |K|^delta, which in Cholesky coordinates is + 2*delta * sum(psi). One line on the log-posterior in each gradient path (logp_and_gradient, logp_and_gradient_full) and +2*delta on each psi-bar entry in the adjoint. Cost O(p) per leapfrog step inside an O(p^3) gradient; effectively free. delta is plumbed through GGMGradientEngine::rebuild and stored on the engine. GGMModel exposes a set_determinant_tilt(delta) setter that forwards on the next ensure_constraint_structure() rebuild; the value is also carried in the copy constructor so per-chain clones target the intended posterior. Currently consumed only by the NUTS path. The MH ratios in ggm_model.cpp do not yet include the corresponding +delta * (log|K_prop| - log|K_curr|) term, so this is safe only when no MH moves fire (i.e. sample_ggm_prior with edge_selection = false). The MH-path tilt will land before delta is exposed on bgm().
The function samples from a prior whose density is specified on the partial-association scale K_yy = -K/2, not on the raw precision K, so "precision" was misleading. Output samples are still entries of K. Renames the R wrapper, the Rcpp export (sample_ggm_prior_cpp), the internal C++ function, the test file, and the docstring; regenerates RcppExports and roxygen docs to match.
Parallel of D for GGM. Adds a non-negative tilt parameter delta to the mixed-MRF Kyy block: multiplies the prior by |Kyy|^delta, which in Cholesky coordinates is + 2*delta * sum(psi). Two added lines per gradient path (logp and psi_bar) in mixed_mrf_gradient.cpp; cost is O(q) per leapfrog step inside an O(q^3) gradient. MixedMRFModel gains a determinant_tilt_yy_ member (default 0.0) and a set_determinant_tilt_yy() setter. The value is carried in the copy constructor so per-chain clones see the intended posterior. Currently consumed only by the NUTS gradient paths; the continuous-block MH ratios in mixed_mrf_metropolis.cpp are not yet updated. mixed_test_logp_and_gradient_full grows a delta argument so the tilt is exercisable from R. Finite-difference tests added to test-mixed-gradient-pfaffian.R cover: - delta = 0 bit-identical to no-tilt call - delta > 0 on full Kyy - delta > 0 on sparse Kyy with random diagonal mass - analytic check: tilted logp - untilted logp == delta * log|Kyy| All pass at max relative error < 1e-5. RcppExports regenerated via Rcpp::compileAttributes(). No regressions in the full test suite (6708 pass, 0 fail).
Companion to commit e4f24cb (NUTS-side GGM tilt). Adds the matching delta * (log|K_prop| - log|K_curr|) term to all six GGMModel MH-ratio sites: - update_edge_parameter - update_diagonal_parameter - update_edge_indicator_parameter_pair (both branches) - tune_proposal_sd (off-diagonal and diagonal passes) The log-determinant ratio is computed in O(p) for rank-2 edge updates and O(1) for rank-1 diagonal updates via the matrix-determinant lemma, reusing the cached covariance_matrix_ and the already-set-up precision_proposal_. Existing log_density_impl_edge/diag are refactored to share two new private helpers log_det_ratio_edge/diag; both helpers return exactly the logdet term that those functions previously computed inline, so the refactor is observationally inert at delta = 0. Each tilt addition is guarded by `if (determinant_tilt_ != 0.0)` so the existing default code path remains a single-pass MH ratio with no additional log() call. NUTS and MH paths now both consume determinant_tilt_ consistently; the chain targets the same posterior under either sampler. No regressions in the existing test suite (6708 pass, 0 fail).
Companion to commit 1bb74c7 (NUTS-side mixed-MRF tilt). Adds the matching delta * (log|Kyy_prop| - log|Kyy_curr|) term to the three continuous-block MH-ratio sites in MixedMRFModel: - update_pairwise_effects_continuous_offdiag - update_pairwise_effects_continuous_diag - update_edge_indicator_continuous Adds two private helpers log_det_ratio_yy_edge/diag that compute the log-determinant ratio via the matrix-determinant lemma in O(q) for rank-2 and O(1) for rank-1, reusing covariance_continuous_ and the already-set-up precision_proposal_. The helpers mirror GGMModel::log_det_ratio_edge/diag. Each tilt addition is guarded by `if (determinant_tilt_yy_ != 0.0)` so the default delta_yy = 0 path is bit-identical to the previous code. NUTS and MH now both consume determinant_tilt_yy_ consistently; the chain targets the same posterior under either sampler. No regressions in the existing test suite (6708 pass, 0 fail).
Adds a delta argument to bgm() that propagates the determinant tilt to
both the NUTS and adaptive-Metropolis paths for GGM and mixed-MRF
models. delta = 0 is the default (untilted) and reproduces the current
behaviour bit-for-bit.
R-layer plumbing:
bgm(delta = 0)
-> bgm_spec(delta = 0) # validation + dispatch
-> build_spec_{ggm,mixed_mrf} # stored on spec$prior$delta
-> run_sampler_{ggm,mixed_mrf} # forwards to C++ entry point
-> sample_{ggm,mixed_mrf}(delta = ...)
C++-layer plumbing:
sample_ggm calls model.set_determinant_tilt(delta)
sample_mixed_mrf calls model.set_determinant_tilt_yy(delta)
bgm_spec rejects delta > 0 for pure-ordinal models (model_type "omrf"
or "compare") since there's no precision matrix to tilt. Negative,
non-finite, or non-scalar delta values produce a clear error early in
bgm_spec().
New test file test-bgm-delta.R covers:
- NUTS path: delta > 0 shifts tr(K) upward vs delta = 0 (GGM)
- MH path: delta > 0 shifts tr(K) upward vs delta = 0 (GGM)
- Pure-ordinal model rejects delta > 0 with informative message
- Invalid delta (negative, NA, non-scalar) rejected at the validator
RcppExports regenerated via Rcpp::compileAttributes(). Full suite:
6714 pass, 0 fail.
The copy constructor initialised pcg_lambda_cache_ before determinant_tilt_, but determinant_tilt_ is declared first in the class. C++ always initialises in declaration order, so the listing was misleading and triggered -Wreorder-ctor across every translation unit that includes ggm_model.h.
The previous reorder fix swapped the trailing pair but left determinant_tilt_ near the end of the init list. determinant_tilt_ is declared just after target_accept_ near the top of the private section, so the init list still triggered -Wreorder-ctor against theta_. Move determinant_tilt_ to immediately after target_accept_ to match.
Three new slow tests gated behind BGMS_RUN_SLOW_TESTS: - GGM NUTS SBC at delta=1 (p=3, R=200), with a tilt-aware prior sampler using the shifted-shape Gamma proposal + (|K|/prod(K_ii))^delta acceptance from the spikeslab manuscript §sec:tilt-empirics. - GGM NUTS-vs-MH posterior moment concordance at delta=1 (p=4). - Mixed-MRF NUTS-vs-MH posterior concordance at delta=1 (Kyy block, no edge selection). Regenerate man/bgm.Rd via devtools::document() to pick up the delta parameter exposed by 8a9f7cb.
Commit 987cc8b renamed sample_precision_prior to sample_ggm_prior but left the topic reference in _pkgdown.yml pointing at the old name, causing build_reference_index() to fail on the missing topic.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #106 +/- ##
==========================================
+ Coverage 86.52% 87.36% +0.83%
==========================================
Files 77 77
Lines 13354 13441 +87
==========================================
+ Hits 11555 11743 +188
+ Misses 1799 1698 -101 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds the determinant-tilt prior$|K|^{\delta}$ as an optional modifier on the continuous-precision block of both the GGM and the mixed-MRF Kyy. With $\delta = 0$ (default) the prior is unchanged; with $\delta > 0$ , the prior gains the factor $|K|^{\delta}$ , which softly repels the chain from the positive-definite cone boundary. Motivated by the determinant-tilted spike-and-slab construction of the companion paper at $q$ and demonstrates that $\delta \approx 1$ recovers a usable prior bulk in that regime.
~/SV/spikeslab/, which documents the cone-interior collapse of the unmodified discrete spike-and-slab at moderate-to-largeThe default is intentionally$\delta = 0$ in this PR so the change is fully backward-compatible. A follow-up PR will introduce a dimension-adaptive default (
δ(q) = c · log q, per the companion paper's empirical scaling rule); see dev/plans/backlog/hierarchical-ggm-degord-rr.md Stage 1.Changes
C++ — GGM (
src/models/ggm/)ggm_gradient.{h,cpp}: NUTS gradient addsdelta * d log|K| / d thetaalong the Cholesky parameterisation.ggm_model.{h,cpp}: MH paths (edge-toggle, edge-update, diagonal) adddelta * (log|K_prop| - log|K_curr|)via the rank-1/rank-2 matrix-determinant lemma in O(p)/O(1). Newset_determinant_tilt()accessor; forwarded to the gradient engine on rebuild.C++ — Mixed MRF (
src/models/mixed_mrf/)R API
bgm()gainsdelta = 0argument with roxygen documenting the partial-association convention and the PD-cone-boundary rationale.sample_ggm_prior()(renamed fromsample_precision_priorin987cc8b) gains the samedeltaargument.man/bgm.Rdregenerated.Tests (gated behind
BGMS_RUN_SLOW_TESTS)test-sbc-ggm.R: new SBC test attest-ggm-nuts.R: new NUTS-vs-MH posterior moment-concordance test attest-mixed-nuts.R: new M.2T NUTS-vs-MH concordance for the Kyy block atTest plan
R CMD check --as-cran: 0 errors / 0 warnings / 0 notes (local, 4m 20s).BGMS_RUN_SLOW_TESTS=true devtools::test()onsbc-ggm|ggm-nuts|mixed-nuts): 1196/1196 assertions, 0 failures, 0 skips (2.4 min).Companion / follow-up
~/SV/spikeslab/manuscript.tex(determinant-tilted spike-and-slab construction; dimension-adaptive scaling rule).δ(q) = 0.5 · log(q)exposed viadelta = NULL.sample_ggm_prior(spec = "joint")for SBC under the joint specification.See dev/plans/backlog/hierarchical-ggm-degord-rr.md for the full multi-stage plan.