Skip to content

fix(marginal): keep Gauss-Hermite weights finite for q >= 371 (#2110) - #2354

Open
seonghobae wants to merge 1 commit into
mainfrom
seonghobae/moa-2110-gh-rule
Open

seonghobae wants to merge 1 commit into
mainfrom
seonghobae/moa-2110-gh-rule

Conversation

@seonghobae

@seonghobae seonghobae commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Fixes the marginal._gh part of #2110.

Problem

numpy.polynomial.hermite_e.hermegauss overflows its weight formula from q = 371 (numpy 2.5.3). The weights then sum to 0 or NaN, so marginal._gh returned NaN weights. _gh feeds the NumPy marginal estimators, fitstats and linking, so any of them evaluated at a study-setting node count of 371 or more got NaN quadrature.

Change

  • New private helper fast_mlsirm/_gauss_hermite.py::probabilists_gauss_hermite(q).
    • Where the normalized hermegauss rule is finite, it returns that rule unchanged, so results for q <= 370 stay bit-identical.
    • Otherwise it falls back to the Golub–Welsch Jacobi eigen-rule. That rule mirrors the Rust core quadrature.rs::gauss_hermite_probabilists (alpha_k = 0, beta_k = k, symmetrized, unit-sum weights).
    • The docstring carries APA 7 citations with the same locators already verified in quadrature.rs.
  • marginal._gh calls the helper. The incorrect comment that hermegauss handles any q is removed. There is still no node-count cap (fix(quadrature): remove unsourced numeric defaults for quadrature node counts in monotonicity/bifactor APIs #1929).

Not in this PR

Verification (local, Python 3.12, numpy 2.5.3, macOS arm64)

  • RED on the unmodified code: the new tests/test_gauss_hermite_high_q.py gave 6 failed / 9 passed. Every q >= 371 case failed with non-finite weights.
  • GREEN: the same file gives 15 passed.
  • Checks covered: q ∈ {371, 400, 481, 961, 1000} give finite, ascending, exactly symmetric weights that sum to 1. The N(0, 1) moments E[x²] = 1, E[x⁴] = 3 and E[x⁶] = 15 are reproduced. For q ∈ {1, 2, 7, 21, 121, 241, 370} the output is bit-identical to normalized hermegauss.
  • Regression check: 36 existing test files touching marginal, fitstats, linking, paper features, Rust parity and cov_e, plus the new file, gave 697 passed, 1 skipped, exit 0.
  • ruff is not installed in the local venv, so it was not run. Hosted lint will cover it.

Summary by CodeRabbit

  • Bug Fixes
    • Improved numerical reliability of Gaussian quadrature at high node counts, with finite, symmetric nodes and normalized weights.
    • Preserved validation for invalid node counts and accurate quadrature results across tested counts.
  • Tests
    • Added coverage for high-count quadrature behavior, weight stability, and normal-moment accuracy.

numpy hermegauss overflows its weight formula from q = 371, so
marginal._gh returned NaN weights for study-setting node counts.
Return the normalized hermegauss rule unchanged where it is finite and
fall back to the Golub-Welsch Jacobi eigen-rule the Rust core uses
otherwise. No node-count cap (#1929).
@coderabbitai

coderabbitai Bot commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: ContextualWisdomLab/fast-mlsirm/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 32f8b442-5032-463f-b148-a2665fb644aa
📥 Commits

Reviewing files that changed from the base of the PR and between a0d7958 and 3b97e83.

📒 Files selected for processing (3)
  • python/fast_mlsirm/_gauss_hermite.py
  • python/fast_mlsirm/estimators/marginal.py
  • tests/test_gauss_hermite_high_q.py

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The change adds a shared probabilists’ Gauss–Hermite helper with a Golub–Welsch fallback. The marginal estimator delegates node and weight generation to the helper. New tests cover high node counts, numerical properties, lower-count equivalence, and invalid counts.

Changes

Gauss–Hermite quadrature

Layer / File(s) Summary
Quadrature generation and fallback
python/fast_mlsirm/_gauss_hermite.py
Adds probabilists_gauss_hermite, which returns normalized NumPy results when they pass validity checks and otherwise uses a Golub–Welsch eigendecomposition. The fallback symmetrizes nodes and weights and handles q == 1 directly.
Marginal estimator integration and validation
python/fast_mlsirm/estimators/marginal.py, tests/test_gauss_hermite_high_q.py
Updates _gh to use the shared helper while retaining its q >= 1 validation. Tests check high-count numerical properties, exact results against normalized hermegauss for selected counts, log weights, and invalid counts.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to 3b97e

No actionable issue remains before merge, subject to normal test and lint checks.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.44% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 9 functions across 3 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the fix: keeping Gauss–Hermite weights finite for node counts q ≥ 371.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🛠️ Fix failing CI checks 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

This branch has not been deployed

No deployments
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