Skip to content

The polygamma functions, and the derivative of the factorial - #2068

Merged
Rafael-SOWNet merged 2 commits into
masterfrom
the-polygamma-function
Oct 22, 2026
Merged

Rafael-SOWNet merged 2 commits into
masterfrom
the-polygamma-function

Conversation

@Rafael-SOWNet

Copy link
Copy Markdown
Member

Part of #171.

The polygamma functions are nodes. polygamma(n, z) is psi^(n)(z), the (n + 1)-th derivative of ln Gamma(z). digamma(z) is polygamma(0, z), and prints that way.

  • Parsing and printing. Both names are parsed, and printed in text, LaTeX (\psi, \psi^{(n)}) and SymPy (digamma, polygamma). Before, digamma(1) was read as the variable digamma times 1, and polygamma(1, 1) did not parse.
  • Derivatives. Each order differentiates to the next. An order that depends on the variable declines.
  • Domain. The condition is a whole order and an argument other than 0, -1, -2, ....
  • The factorial's derivative. It is x! * digamma(x + 1), where it declined (Differentiating a factorial or gamma answers NaN, which claims the derivative does not exist #958). So gamma(x) differentiates to (x - 1)! * digamma(x).

Evaluation is to the working precision, for every complex argument but the poles, where it is NaN.

  • Left of Re z = 1/2. Reflection (DLMF 5.15.6), with the derivatives of cot(pi z) as polynomials in cot.
  • Right of it. The recurrence (5.15.5) moves the argument to Re w >= R, with R the working digits plus n. Then the asymptotic series (5.11.2, 5.15.8) is summed to the working precision.
  • Bernoulli numbers. Exact, from the tangent numbers by Brent and Harvey's integer recurrence, and cached.

Results:

Precision Accuracy against mpmath Cost of a fresh evaluation
100 digits to the last digit, at the test file's points about 2–9 ms
300 digits to the last digit, at 2100-digit references about 0.1 s
2000 digits to the last digit, at 2100-digit references 2–6 s

The 300- and 2000-digit points are digamma(3/2), polygamma(3, 7/3) and digamma(-7/3 + 2i).

Not in this PR.

  • Special values. They stay as written, since digamma(1) = -gamma wants a symbol for Euler's constant, which the library does not have.
  • Compiling and the interval evaluator. Neither takes the node yet.
  • Integration rules. int psi(x) dx = ln Gamma(x) and the rest are not here.
  • The inverse half of the issue. x! = y has no closed-form inverse, and an equation in either function is left as the set of x for which it holds.

PolygammaTest covers:

  • values on the real line and off it, against mpmath at 130 digits: reflection, large arguments, orders 0 to 5;
  • the poles;
  • the factorial's derivative at 3, which is 7.53670601059080…;
  • each order differentiating to the next;
  • parsing and printing round trips.

Results:

  • Unit suite: passes (16,767).
  • Corpus: the full Rubi corpus, run against the 2.6.0 run on the same harness (c614b2c8), is 48,305 of 48,305, with no row moved and no answer's allocation grown.
  • Parser: regenerated, with its classes internal.
  • PublicApi.txt: gains only the node, the kernel and the two factories.

🤖 Generated with Claude Code

https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura

polygamma(n, z) is psi^(n)(z), the (n + 1)-th derivative of ln Gamma(z),
and digamma(z) is polygamma(0, z) and prints so. Both are parsed and
printed in text, LaTeX and SymPy; neither name was recognised, so
digamma(1) was the variable digamma, and polygamma(1, 1) did not parse.
Each order differentiates to the next, and an order that depends on the
variable declines. The derivative of x! is x! digamma(x + 1), where it
declined (#958), so gamma(x) differentiates to (x - 1)! digamma(x).

It is evaluated to the working precision anywhere in the complex plane
but at 0, -1, -2, ..., its poles: reflected left of Re z = 1/2 (DLMF
5.15.6), with the derivatives of cot(pi z) as polynomials in cot; moved by
the recurrence (5.15.5) to Re w at least the working digits; and summed by
the asymptotic series (5.11.2, 5.15.8), with the Bernoulli numbers exact
from the tangent numbers by Brent and Harvey's recurrence. It agrees with
mpmath to the last digit at 100, 300 and 2000 digits. Special values stay
as written, since digamma(1) = -gamma wants a symbol for Euler's constant.

Two derivative tests used the factorial as the node that cannot be
differentiated; they use a polygamma function of a varying order.

Part of #171.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura
The server's syntax document lists every function the grammar reads, and
its test fails on a name the grammar accepts that the document does not.

Part of #171.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura
@Rafael-SOWNet
Rafael-SOWNet merged commit db5573d into master Oct 22, 2026
38 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in AngouriMath Oct 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant