Skip to content

Accurate derivatives of gamma_inc and gamma_inc_dx - #871

Draft
devmotion wants to merge 4 commits into
dw/dual-float-constantsfrom
dmw/gamma_inc_dx
Draft

devmotion wants to merge 4 commits into
dw/dual-float-constantsfrom
dmw/gamma_inc_dx

Conversation

@devmotion

Copy link
Copy Markdown
Member

Alternative to #862, based on JuliaMath/SpecialFunctions.jl#568.

#862 avoids the overflow of exp(-x) * x^(a - 1) / gamma(a) by computing the x-derivative of gamma_inc in log space, but the cancellation in the exponent makes it inaccurate for large a (relative error ~7e-10 at a = 1e6 and ~1e-5 at a = 1e10 in Float64; ~16% at a = 1e6 in Float32).

SpecialFunctions#568 adds a public gamma_inc_dx(a, x) = x^(a - 1) e^(-x) / Γ(a) (the x-derivative of gamma_inc(a, x)[1]), computed without cancellation, together with internal helpers for its derivatives in a and x. This PR:

  • uses SpecialFunctions.gamma_inc_dx for the derivative of gamma_inc(a, x, ind) with respect to x, if it is available, and falls back to the current formula otherwise (to be removed once SpecialFunctions >= 2.10 is required);
  • defines Dual rules for gamma_inc_dx in both arguments (via @define_binary_dual_op, so mixed tags work), which makes nested derivatives of gamma_inc in x accurate, including at x = 0 and at the poles of digamma(a);
  • throws an ArgumentError for derivatives of gamma_inc with respect to a, instead of a MethodError from SpecialFunctions internals; Duals with zero partials for a are supported.

Tests compare first derivatives (Float32 and Float64), gradients, Hessians and nested mixed derivatives against BigFloat references, and cover NaN-safe mode. Tests that require gamma_inc_dx are guarded on isdefined(SpecialFunctions, :gamma_inc_dx).

Dependencies:

Locally (with a stand-in for #855), test/DualTest.jl and test/DerivativeTest.jl pass against the SpecialFunctions#568 branch and against SpecialFunctions 2.9.1, with NaN-safe mode on and off, and there are no new method ambiguities.

🤖 Generated with Claude Code

@codecov

codecov Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.66667% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 91.20%. Comparing base (8c66edc) to head (36121d3).

Files with missing lines Patch % Lines
src/dual.jl 91.66% 1 Missing ⚠️
Additional details and impacted files
@@                     Coverage Diff                     @@
##           dw/dual-float-constants     #871      +/-   ##
===========================================================
- Coverage                    91.22%   91.20%   -0.02%     
===========================================================
  Files                           11       11              
  Lines                         1083     1092       +9     
===========================================================
+ Hits                           988      996       +8     
- Misses                          95       96       +1     

☔ 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.

Use SpecialFunctions.gamma_inc_dx (SpecialFunctions >= 2.10) for the
derivative of gamma_inc with respect to x, and define Dual rules for
gamma_inc_dx in both arguments. Derivatives of gamma_inc with respect
to a throw an informative ArgumentError instead of a MethodError.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@devmotion
devmotion changed the base branch from master to dw/dual-float-constants November 3, 2026 21:50
- Drop the redundant `<:Real` bounds and share the constant-`a` check
- Bump version to 1.5.1 (on top of #855)
- Test the gradient of `DiffResults.hessian!`, which uses nested duals
- Test the derivative at `x = 0` for `a = 1` (from #862)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
devmotion and others added 2 commits November 3, 2026 23:11
If the closed form of the derivative of `gamma_inc` overflows, compute it
in log space instead (as proposed in #862).

Co-Authored-By: Nathan Chandrasekar <322284620+vera-rubin@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`exp((a - 1) * log(x) - x)` overflows the exponent range of MPFR on Windows
for `a = x = 1e10`, which would make the reference NaN.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

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