Skip to content

feat: extend symbolic integration across five benchmark gaps - #441

Closed
KingArth0r wants to merge 1 commit into
cortex-js:mainfrom
KingArth0r:feat/integration-benchmark-gaps
Closed

KingArth0r wants to merge 1 commit into
cortex-js:mainfrom
KingArth0r:feat/integration-benchmark-gaps

Conversation

@KingArth0r

Copy link
Copy Markdown
Contributor

Why

This addresses five concrete CE gaps exposed by Integral Benchmark, without changing the benchmark adapter to make the scores look better. Base: 2793af9d.

Area Evidence on main Change and reason
Nonlinear Abs / Sign Integral of Abs(Sin(x)) over [0, 2π] stayed inert, although the equivalent Max expression already worked Activate the bounded exact-root piecewise splitter for nonlinear arguments. Preserve the affine kink path, including enclosing-variable ranges in nested integrals.
Repeated patterns Fract(x) over [0, 1000000.5] exceeded the crossing budget Closed integer-cell sums, including affine weights, plus period-and-remainder reduction for Abs/Sign of affine Sin/Cos. Work no longer grows with the number of repeated cells.
Rubi reliability and loading The beta-half integral returned π without Rubi but stayed inert with Rubi; 6,574 rules contain only 4,016 distinct LHS/variable pairs Try a closed built-in primitive when provider endpoints are unusable, retaining the existing pole/endpoint checks. Reuse the pure endpoint result instead of evaluating it twice. Compile identical patterns once per compilation call, retaining each rule's order, guards, bindings, RHS and skip identity. Reject invalid step budgets before compilation.
Infinite jump sets Fract(1/x) and Floor(1/x) on [0,1] were both inert A convergent reciprocal-cell sum gives 1−EulerGamma for the fractional part. Comparison with c/x establishes divergence for Floor/Ceil. Include scaling, partial initial cells and reversed bounds.
Primitives, substitution and improper moments Erf, BesselJ(1,x), PolyGamma(0,x), exp(x+exp(x)), and x/(exp(x)−1) exposed missing routes Add affine special-function primitives, analytic LogGamma differentiation, bounded reverse-chain recognition inside nested exponential sums, and convergence-checked Bose moments.

Correctness and scope

  • Nonlinear cuts reuse the existing complete-root solver and exact irrational/transcendental ordering; no numerical root guesses.
  • Unknown partitions remain inert. The existing cell-count cap is not increased.
  • Floor/Ceil/Fract affine weights use zeroth/first cell moments; higher polynomial weights and arbitrary periodic compositions are not implemented here.
  • Reciprocal jump sums require positive c and a finite positive upper bound; the explicit harmonic-number construction is capped at 128 terms. This is not an unrestricted infinite-series integrator.
  • New special primitives cover Erf/Erfc, order-one BesselJ/BesselI, and the digamma/polygamma ladder with affine arguments. Definite polygamma integrals require a proven positive argument interval, so the new primitives cannot bypass the non-positive-integer pole family.
  • Bose moments require a positive decay scale and integer degree 0–32. Degree zero diverges; positive degrees return n!·Zeta(n+1)/a^(n+1). See DLMF 25.5.1.
  • New reductions respect purity, library-name shadowing, bound variables and existing cancellation budgets.
  • Compiled patterns are never shared across engines. No default timeout was increased, and no failing assertion was weakened.
  • No new dependencies or platform-specific scripts.

Profiling and benchmark evidence

Reproducible commands and raw measurements are checked in:

  • scripts/profile-integration-gaps.ts
  • benchmarks/integration-gaps-profile.json

The baseline CPU profile attributed about 18.20 seconds of an 18.89-second cold rule load to compileRuleDocs. Pattern reuse avoids 2,558 duplicate compilations (38.9%) while preserving all 6,574 rules with zero skips.

Three alternating-order, fresh-process compilation samples, retaining the full compiled output in both variants, had medians of 5.42s uncached and 4.27s cached (about 21% lower locally). No other agent validation jobs ran concurrently. One cached sample was slower than its pair; all raw samples are included. This small experiment is not a universal speedup claim or a CI timing threshold. Idempotent same-engine reload was already fast and remains so; fresh-process benchmark startup must still be measured separately from solving.

Using the unchanged local Integral Benchmark harness/corpora:

  • 68-case default pilot: 53 → 57 independently checked, with no previously verified case regressing.
  • 20-case discrete set: 15 → 19 checked, including the divergence classification.
  • Digamma now produces LogGamma(x), but the verifier lacks that operator; it is explicitly not counted as verified.
  • The remaining discrete miss is the adapter's unsupported Which, not CE.
  • These failure-driven fixtures are not representative CAS-wide rankings. The full 64,718-case Rubi queue was not run or resumed.

Verification

  • Final focused run: 524 tests and 161 snapshots passed across the new coverage, pattern-cache, piecewise and calculus suites.
  • Broader 45-suite run: 2,596 passed, 2 skipped, 354 snapshots passed. Its three failures were the affine nested-integral regression (fixed; full calculus suite rerun passed) and two existing Rubi wall-clock-sensitive cases. Both Rubi cases subsequently passed reruns; the remaining R30 case also passed on unchanged main and then on the final feature branch with no competing validation jobs. The full 45-suite command was not repeated after those fixes.
  • The diagnostic Rubi driver also closed both cases, reporting 10,178 and 154,774 steps with no internal hang guards firing. Raw timings and test guard settings are included in the JSON evidence.
  • All 508 source files passed ESLint with CRLF normalized to LF in memory, without modifying the Windows checkout. The ordinary raw-Windows run reports existing CRLF formatting errors; changed-file ESLint and formatting checks passed directly.
  • TypeScript checks passed for both public entry points, the profiling script and new tests.
  • No circular dependencies; git diff --check clean.
  • Local runtime: Node 22.14.0. The full repository test/corpus pipeline and Node 26 were not run locally.

The broader run caught an affine nested-integral dispatch regression; that was fixed and pinned by an explicit ∫∫|x−y| test. Regression coverage also includes independently enumerated weighted cells, shifted/negative-frequency periods, exact irrational switches, reciprocal convergence/divergence, derivative checks at regular points, rejected domains, provider fallback/cancellation, binding isolation, and duplicate-pattern metadata preservation.

Benchmark-only adapter/verifier work remains separate from this PR.

arnog added a commit that referenced this pull request Oct 15, 2026
… precision, integration gaps

PR #436 (enumeratio, fix #434): the JavaScript target lowers HurwitzZeta,
LerchPhi, PolyLog, EllipticK, the complete EllipticE, Hypergeometric2F1 and
LambertW to the interpreter's complex kernel in `auto` and `complex` mode
where the operand facts do not prove the value real; `strict` keeps the real
kernel and its NaN; a complex operand takes the complex kernel in every mode.
The verdict lives in one place (`complexContinuation`), read by both
`isComplexValued` and the emitters. The GLSL and WGSL targets decline a
provably complex value, now including a positive integer order on the cut
`z > 1` (`PolyLog(2, 3)`, `LerchPhi(3, 2, 1)`). `Arcsec` and `Arccsc` of an
operand of unknown magnitude type `complex | infinity | nan` instead of
`number`, so the compiled lanes read the complex value.

PR #440 (enumeratio, fix #439): `Argument` of a complex value passes the
bignum parts to `Arctan2`, so `N(Argument(e + iπ), 25)` carries 25 digits.
Also from #439: `Transpose` of an operand with no known shape is typed
`unknown` (a union such as `matrix | vector` is transposed member by
member), so `MatrixMultiply(q, Transpose(q))` with a free `q` stays
unevaluated instead of an `incompatible-type` error.

PR #441 (KingArth0r): definite integrals of more families evaluate in
closed form — an absolute value or sign of a non-affine argument is split at
its exact roots; integer-cell sums (Floor, Ceil, Fract with an affine
weight) and `|sin(kx + m)|` over many periods no longer grow with the cell
count; `∫₀¹ {1/x} dx = 1 − γ` and `∫₀¹ ⌊1/x⌋ dx = +∞`; primitives for Erf,
Erfc, BesselJ(1, ·), BesselI(1, ·), Digamma, Trigamma and PolyGamma of an
affine argument (and `d/dx LogGamma = Digamma`); the nested exponential
`∫ e^{x + e^x} dx`; the Bose moments `∫₀^∞ xⁿ/(e^{ax} − 1) dx`. With the Rubi
rules loaded, a provider antiderivative with no value at a bound falls back
to the built-in one. Loading the rules compiles each distinct pattern once,
and an invalid `stepBudget` is rejected before compilation. The PR's
profiling script and JSON record are not included.

Review fixes on top of the PRs: a user definition with its own `compile`
handler keeps its own lane; compiled `HurwitzZeta(1, z)` for a non-real `z`
is the pole; the period shortcut declines outside radian mode; exact
coefficients in the cell sums stay exact; a polygamma integral between two
consecutive poles evaluates; the infinite-bound inert decision reads the
heads that contain the variable.

ROADMAP: the antiderivative of Sin and Cos ignores the degree angular unit
(found by the review; pre-existing).

Fix #434
Fix #439

Co-authored-by: enumeratio <314378874+enumeratio@users.noreply.github.com>
Co-authored-by: KingArthur <118565558+KingArth0r@users.noreply.github.com>
@arnog

arnog commented Oct 15, 2026

Copy link
Copy Markdown
Member

Merged by hand onto main as 403a216: the source, the tests and a CHANGELOG entry. The profiling script and its JSON record were left out of the tree. The review added: the period shortcut declines outside radian mode, exact coefficients stay exact, and a polygamma integral between two poles evaluates. Thank you.

@arnog arnog closed this Oct 15, 2026
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