Skip to content

fix(distributions): improve lower tail numerical stability in Moyal logcdf (#8437) - #8438

Open
sonusharma6-dsa wants to merge 4 commits into
pymc-devs:mainfrom
sonusharma6-dsa:fix/8437-moyal-logcdf-lower-tail
Open

sonusharma6-dsa wants to merge 4 commits into
pymc-devs:mainfrom
sonusharma6-dsa:fix/8437-moyal-logcdf-lower-tail

Conversation

@sonusharma6-dsa

Copy link
Copy Markdown

Description

In pymc.distributions.continuous.Moyal.logcdf, res was previously computed as pt.log(pt.erfc(pt.exp(-scaled / 2) * (2**-0.5))). For large negative value (scaled = (value - mu) / sigma << 0), pt.exp(-scaled / 2) grows large, causing pt.erfc(...) to underflow to 0.0 and pt.log(0.0) to return -inf.

This PR switches to pt.erfcx(u) for u > 1.0 using the identity log(erfc(u)) = log(erfcx(u)) - u**2, preventing premature numerical underflow to -inf in the lower tail while maintaining double-precision accuracy across all inputs.

Added unit test test_moyal_logcdf_lower_tail in tests/distributions/test_continuous.py.

Related Issue

Checklist

Type of change

  • New feature / enhancement
  • Bug fix
  • Documentation
  • Maintenance
  • Other (please specify):

@sonusharma6-dsa
sonusharma6-dsa force-pushed the fix/8437-moyal-logcdf-lower-tail branch from a093327 to c9d642b Compare September 14, 2026 20:24
@read-the-docs-community

read-the-docs-community Bot commented Sep 14, 2026 •

Copy link
Copy Markdown

@sonusharma6-dsa

Copy link
Copy Markdown
Author

pre-commit.ci autofix

@drkotireddysaripalli

Copy link
Copy Markdown

The added lower-tail regression test appears to need a different reference. At a9e414d, line 963, expected comes from st.moyal.logcdf.

In SciPy 1.18.0, moyal_gen does not override _logcdf; its _cdf evaluates erfc(exp(-x/2)/sqrt(2)). The inherited rv_continuous._logcdf takes log(_cdf) below the median. That reference therefore has the same CDF-before-log underflow problem. Equal -inf values can satisfy assert_allclose (confirmed locally with NumPy 2.3.5), while a finite corrected result would disagree with that reference.

For z = (x - mu) / sigma, the CDF identity is F(x) = erfc(exp(-z/2)/sqrt(2)) = 2*Phi(-exp(-z/2)). A proposed independent reference using the normal log-CDF function is:

from scipy.special import log_ndtr

# For this test's mu=0, sigma=1 and xs=[-10, -20, -50]:
expected = np.log(2.0) + log_ndtr(-np.exp(-xs / 2.0))
assert np.isfinite(expected).all()
assert np.isfinite(res).all()
np.testing.assert_allclose(res, expected, rtol=1e-5)

I checked the pinned source paths and a standard-library erfc underflow calculation; I have not run the PyMC/SciPy test suite here. This feedback concerns the test reference for these finite lower-tail inputs, without assessing the other changes in this PR.

Prepared with Codex for a source-based numerical-methods clarification. Affiliation: Bharath Healthcare / Pinnacle Blooms Network.

@sonusharma6-dsa

Copy link
Copy Markdown
Author

Thanks for catching this. I missed that scipy.stats.moyal.logcdf has the same underflow problem, so it isn't a reliable reference for this test.

I'll switch to the log_ndtr reference you suggested and add explicit finiteness checks for both the expected and computed values. That should make the test catch the original bug instead of passing on matching -inf values.

Copilot AI balanced review requested due to automatic review settings October 7, 2026 05:47

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

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.

BUG: Moyal logcdf returns -inf in lower tail where value is finite

3 participants