Skip to content

Widen PolyLog(s, z) to a non-integer or complex order; Part of #340 - #358

Merged
arnog merged 3 commits into
cortex-js:mainfrom
enumeratio:polylog-order
Sep 28, 2026
Merged

arnog merged 3 commits into
cortex-js:mainfrom
enumeratio:polylog-order

Conversation

@enumeratio

Copy link
Copy Markdown
Contributor

Part of #340. Depends on #356 (LerchPhi): this branch is on top of it.

PolyLog(s, z) now evaluates at non-integer and complex order through Liₛ(z) = z·Φ(z, s, 1), reusing the LerchPhi kernel rather than a second implementation. PolyLog(s, 1) and PolyLog(s, −1) reduce exactly to Zeta(s) and (2^(1−s) − 1)·ζ(s) for any order. Integer orders are unchanged. Compiles to JavaScript, GLSL and WGSL for real operands.

Numeric policy as for LerchPhi: it stays unevaluated where it can't be accurate. That's past |z| = 1 where LerchPhi declines (#353), and three measured zones near the branch point z = 1, near a positive integer order on the rim, and for real z < 0 with very negative order. Checked against mpmath polylog over s ∈ [−4, 6] (real and complex) and z inside, on and outside the unit disk, on both sides of the cut: no answered value off by more than 6e-13.

…z·Φ(z,s,1) on the LerchPhi kernel; compile to JavaScript, GLSL and WGSL for real operands. Part of cortex-js#340

- numerics/polylog.ts: polylogOrderReal/polylogOrderComplex reusing lerchPhiReal/lerchPhiComplex at base point a = 1, plus reliability guards (seriesUnreliable, nearBranchPointUnreliable, nearPositiveIntegerOrderUnreliable) that decline rather than certify a value past 1e-12 relative error
- library/special-functions.ts: evaluatePolyLog widened for non-integer/negative order past the existing integer-order kernel; polylogReduce's z = 1 and z = -1 exact forms generalized from integer order to any order (Liₛ(1) = ζ(s), Liₛ(-1) = (2^(1-s) - 1)ζ(s))
- compilation/javascript-target.ts, compilation/gpu-target.ts: real-only PolyLog lowering (_SYS.polyLog, _gpu_poly_log), the latter appended to the Lerch preamble blob so it inherits _gpu_lerch_phi's dependency scan for free
- test/compute-engine/polylog-order.test.ts: table-driven cases cross-checked against mpmath, covering integer order (unchanged), non-integer real/complex order inside the disk, the z = ±1 exact reductions, past |z| = 1 and on the rim, the decline guards, and the JS/GPU lanes
- test/compute-engine/special-functions.test.ts: updated the now-stale "stays symbolic outside the kernel domain" assertion
- CHANGELOG.md, src/epsil/docs/library.md (regenerated), ROADMAP.md
arnog and others added 2 commits September 28, 2026 16:43
# Conflicts:
#	CHANGELOG.md
#	ROADMAP.md
…plex order)

Dual review (Codex + Claude), every value checked against mpmath.

Correctness:
- The compiled JavaScript and GPU lanes sent every order through the
  widening kernel, bypassing the exact reductions and the integer-order
  kernel: compiled PolyLog(3, -2) was NaN (interpreter -1.66828…),
  PolyLog(-6, 0) NaN, PolyLog(0, 1) -0.5 instead of the pole. A dispatcher
  now handles z = 0, the orders 1, 0, -1, integer orders >= 2 and the
  rational forms for -2..-12 before the kernel, on both lanes.
- The near-integer guard looked only at Re(s): s = 5 + 1e-6i on the rim
  returned values off by up to 3e-4. The distance is now measured in the
  complex plane.
- The eta identity at z = -1 cancelled for a float order near 1
  (PolyLog(1.000000000001, -1) was off by 6e-10); the kernel answers there.
- The whole real axis z < -1 declined for every non-integer order although
  the value is real: Jonquière's inversion now answers it where it measures
  accurate (PolyLog(1.5, -3) = -1.679089730504828); what remains is in
  ROADMAP.
- The z = 1 guard declined 0.98 < |z| < 1.02, including ordinary points
  such as PolyLog(2.5, 0.999); measured, the kernel is accurate to 1e-12
  down to |z − 1| = 1e-3, which is the new radius.
- The series guard declined a positive real z with a negative order where
  every term is positive (PolyLog(-3.5, 0.5) stayed symbolic); it applies
  to the measured complex region only.
- Negative integer orders -2..-12 use their rational closed form, so
  PolyLog(-2, 1/2) is the exact 6 (it stayed symbolic, and .N() gave
  5.999999999999999).
- The type handler said `real` for a real z > 1 (PolyLog(1.5, 2) is
  complex); it claims `real` only for z proven <= 1 or an integer order <= 0.
- A float order gives a float closed-form result (PolyLog(0.0, 1/2)).

Tests and conventions: `isComplex` spelling; lock-in tests for the z = ±1
ordering; the compiled parity check no longer accepts NaN on both sides as
agreement; corrected test comments; CHANGELOG under [Unreleased].

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@arnog
arnog merged commit 5cbd278 into cortex-js:main Sep 28, 2026
@arnog

arnog commented Sep 28, 2026

Copy link
Copy Markdown
Member

Thanks, merged (after #356), with a review pass on your branch as 145cdaed. The main corrections:

  • The compiled JavaScript and GPU cases sent every order through the widening kernel, so compiled PolyLog(3, -2) was NaN and PolyLog(0, 1) was $−0.5$ instead of the pole. A dispatcher now handles $z = 0$, the orders $1, 0, −1$ , integer orders $≥ 2$ and the rational forms for $−2..−12$ first, for both cases.
  • The near-integer guard looked only at $Re(s): s = 5 + 1e-6i$ on the rim returned values off by up to $3e−4$. The distance is now measured in the complex plane.
  • The whole real axis $z &lt; −1$ declined for every non-integer order although the value is real; Jonquière's inversion answers it where it measures accurate (PolyLog(1.5, -3) = −1.679089730504828). What remains is tracked in ROADMAP.
  • The $z = 1$ guard declined $0.98 &lt; |z| &lt; 1.02$; measured, the kernel is accurate to $1e−12$ down to $|z − 1| = 1e−3$, which is the new radius. The series guard no longer declines a positive real $z$ with a negative order.
  • Negative integer orders $−2..−12$ use their rational closed form (PolyLog(-2, 1/2) is the exact 6); the type handler claims real only for $z$ proven $≤ 1$ .

Two limits of the current hurwitzZetaComplex (a negative order with a complex base point; the machine zeta near a small negative order) are recorded in ROADMAP; they bound the inversion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants