Skip to content

bgmCompare: persistent sweep state and current-state normalizer cache#167

Merged
MaartenMarsman merged 3 commits into
developfrom
perf/bgmcompare-sweep-state-v2
Jul 10, 2026
Merged

bgmCompare: persistent sweep state and current-state normalizer cache#167
MaartenMarsman merged 3 commits into
developfrom
perf/bgmcompare-sweep-state-v2

Conversation

@MaartenMarsman

Copy link
Copy Markdown
Collaborator

Two commits removing the main redundancies in the bgmCompare sampler. Follow-up to #166.

Persistent per-group sweep state

CompareSweepState, owned by the Gibbs runner and threaded by reference, holds the double observation matrices (whole and per group), the group-specific effective pairwise weights, and the residual matrices obs_double[g] * pairwise_group[g]. It replaces per-use rebuilds: the AM pairwise sweep and proposal-sd tuner no longer reassemble weight/residual matrices each sweep (accepted moves maintain them in place), the main-effect pseudoposterior reads rest scores from the residuals instead of converting observations and running one GEMV per group per evaluation, and indicator-flip ratios adjust cached rest scores by the effective-weight change. The NUTS path triggers one state rebuild per iteration; imputation refreshes the state once per pass.

Current-state normalizer cache

The sweep state additionally caches the per-variable, per-group pseudolikelihood log-normalizer sums, and metropolis_step_cached() takes the current-state log-posterior as a value (same random-number stream), so each Metropolis proposal evaluates only the proposal instead of both states. Accepted moves store the proposed-state sums; indicator flips invalidate the affected variables; weight rebuilds (NUTS updates, graph initialisation, imputation refresh) invalidate every variable.

Verification

  • Same-seed single-chain draws vs the base (n = 220, V = 7, 2 groups; clean builds): NUTS + selection bitwise identical across 9 seeds; AM + selection + imputation bitwise identical; AM cells without imputation differ only by residual-maintenance float reordering (max sample deviation 2e-8) with bitwise-identical indicator draws.
  • The normalizer-cache commit on its own is bitwise identical to its parent in all four cells.
  • Full test suite with NOT_CRAN: 7000 passed / 0 failed / 0 errors; R CMD check --as-cran: 0 errors / 0 warnings / 2 environmental notes.

Benchmarks (installed -O2 builds vs the base branch; n = 800, V = 16 ordinal, 3 groups, single chain, min of 2)

fit develop this branch
AM, fixed graph 25.8s 8.6s
AM + difference selection 20.3s 8.4s
AM + selection + 3% impute 20.5s 8.7s
NUTS + selection 36.9s 33.8s

The AM gains grow with n and the number of groups (the removed work — observation conversions, per-group GEMVs, current-state re-evaluations — scales with both). NUTS benefits only through the Metropolis indicator flips.

…weights, and residuals

Add CompareSweepState, owned by run_gibbs_sampler_bgmCompare and threaded
by reference through the Gibbs update step. It holds the double observation
matrices (whole and per group), the group-specific effective pairwise
weights, and the residual matrices obs_double[g] * pairwise_group[g].

The state replaces per-use rebuilds:
- the AM pairwise sweep and the proposal-sd tuner no longer rebuild the
  weight and residual matrices each sweep; accepted moves maintain them;
- log_pseudoposterior_main_component reads rest scores from the residual
  matrices instead of converting observations and running one GEMV per
  group per evaluation;
- the indicator-flip ratios read current rest scores from the residual
  matrices and adjust them by the change in the effective weight, removing
  the per-call conversions and GEMVs; accepted pairwise flips update the
  state in place;
- the NUTS path receives the pre-converted observation matrix and triggers
  one state rebuild per iteration;
- imputation refreshes the state once per pass.

Verification: test-bgmCompare.R passes (40, 42 with NOT_CRAN). Same-seed
single-chain regression against the previous commit: NUTS-with-selection
and AM-with-imputation fits are bitwise identical; AM fits without
imputation differ only by residual-maintenance float reordering (max
sample diff 8e-8, posterior-mean diff 3e-8); indicator draws bitwise
identical in all cells.
Add a per-variable, per-group cache of the pseudolikelihood log-normalizer
sums to CompareSweepState, and metropolis_step_cached(), a metropolis_step()
variant that takes the current-state log-posterior as a value and evaluates
only the proposal (same random-number stream).

The main-effect and pairwise-effect component functions accept optional
cached normalizer sums for the current state and optionally return freshly
computed ones. Two shared helpers, metropolis_update_main_effect_cached and
metropolis_update_pairwise_effect_cached, reconstruct the current-state
value from the cache (computing it on a miss), evaluate the proposal in
full, and on acceptance store the proposed-state normalizer sums; the
Metropolis sweeps and the proposal-sd tuner call the same helpers. This
removes the second full evaluation per proposal.

Invalidation: accepted main and pairwise moves store the proposed-state
sums; accepted indicator flips invalidate the affected variables; weight
rebuilds (NUTS updates, graph initialisation, imputation refresh)
invalidate every variable.

Verification: test-bgmCompare.R passes (42 with NOT_CRAN). Same-seed
single-chain regression against the previous commit: all four fits (AM
without selection, AM with selection, AM with selection and imputation,
NUTS with selection) are bitwise identical, including indicator draws;
AM fits run 25-45% faster.
@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.32620% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.07%. Comparing base (2eb802e) to head (494d61e).
⚠️ Report is 1 commits behind head on develop.

Files with missing lines Patch % Lines
src/models/bgmCompare/bgmCompare_sampler.cpp 94.18% 5 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop     #167      +/-   ##
===========================================
+ Coverage    90.98%   91.07%   +0.08%     
===========================================
  Files          104      104              
  Lines        14913    14950      +37     
===========================================
+ Hits         13569    13615      +46     
+ Misses        1344     1335       -9     

☔ View full report in Codecov by Harness.
📢 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 merged commit 733f529 into develop Jul 10, 2026
7 checks passed
@MaartenMarsman MaartenMarsman deleted the perf/bgmcompare-sweep-state-v2 branch July 10, 2026 08:43
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