Skip to content

Return 0 from Gamma CDF for non-positive inputs - #33

Open
arpitjain099 wants to merge 1 commit into
sandialabs:dev/mainfrom
arpitjain099:fix/gamma-cdf-nonpositive-dev
Open

Return 0 from Gamma CDF for non-positive inputs#33
arpitjain099 wants to merge 1 commit into
sandialabs:dev/mainfrom
arpitjain099:fix/gamma-cdf-nonpositive-dev

Conversation

@arpitjain099

Copy link
Copy Markdown

The Gamma distribution is supported on [0, inf), so its CDF should be 0 for every x <= 0. Right now GammaMarginal.cdf returns nonsense there, because _gammainc uses the substitution t = x*u, which only holds for x > 0.

With scale=1.5, on current dev/main:

  • shape=2.0: cdf(-1.0) is about 0.50 and cdf(-5.0) is about 134, so the CDF is not monotonic and leaves [0, 1] entirely.
  • shape=1.0: cdf(-1.0) is negative.
  • shape=0.5: cdf(x) is NaN for x <= 0, including at x=0, since 0 ** (shape - 1) blows up.

scipy.stats.gamma(...).cdf returns 0.0 for all of those.

The fix evaluates the quadrature on the positive part only and masks the rest back to 0. Masked entries get ones substituted before the quadrature so nothing goes non-finite, which keeps the torch autograd graph clean (I checked that d/dx cdf at a positive point still equals the pdf). Positive-x results are untouched.

Tests added for x <= 0 at shape 2.0, for the shape < 1 case where the integrand is singular at the origin, and for monotonicity across a grid spanning zero. All three fail before the change on both backends. After it, packages/pyapprox/tests/probability/ is 1610 passed, 28 skipped, and ruff check packages/pyapprox/src/pyapprox/ is clean.

I based this on dev/main since that is where development seems to happen. Happy to retarget, or to move the guard up into cdf() if you would rather keep _gammainc a raw kernel.

I work on open-source supply-chain security and spend a fair amount of time reading numerical code in national-lab projects, which is how I ran into this one.

The Gamma distribution is supported on [0, infinity), so gammainc(k, x)
is 0 for x <= 0. The substitution t = x*u used by GammaMarginal._gammainc
only holds for x > 0, so a non-positive sample produced a spurious value:
around 0.50 at x=-1 and 134 at x=-5 for shape=2, a negative value for
shape=1, and NaN for shape<1 (where the CDF was also NaN at x=0). That
breaks monotonicity and puts the CDF outside [0, 1].

Evaluate the quadrature on the positive part only and mask the rest to 0.
Masked entries are substituted with ones before the quadrature so they
stay finite and cannot poison the torch autograd graph. Positive-x results
are unchanged.

Signed-off-by: Arpit Jain <arpitjain099@gmail.com>
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