Skip to content

A special function beside an elementary factor is integrated by parts, and so is its square - #1639

Merged
Rafael-SOWNet merged 1 commit into
masterfrom
a-special-function-beside-an-elementary-factor
Oct 1, 2026
Merged

Rafael-SOWNet merged 1 commit into
masterfrom
a-special-function-beside-an-elementary-factor

Conversation

@Rafael-SOWNet

Copy link
Copy Markdown
Member

x Si(b x) sin(b x) was left unevaluated where Si(b x) sin(b x) was not, and so was every square of a special function beside a power of x. Two steps of integration by parts were missing, and both are scoped to a special function of a linear argument.

  • The factor beside the special function, by its polynomial's parts. By parts, x Si(b x) sin(b x) is Si(b x) against x sin(b x). The integral of that factor was taken with parts off, and x sin(b x) needs them. Beside a special function of a linear argument, a polynomial times something else is now integrated by the polynomial's parts, which end in as many steps as its degree. What is left, the special function's derivative times polynomials and elementary functions, is given parts in turn.
  • The remainder of a square, term by term. A square of a special function of b x is two rounds of parts. The remainder of the first comes back as one product over a sum that no rule reads whole: (b x Ei(b x) - e^(b x)) e^(b x)/(b x) for Ei(b x)^2. Its terms, e^(b x) Ei(b x) and e^(2 b x)/(b x), are each answered when asked. So where the remainder after a special function is not answered, its terms are asked one at a time, the ordinary way first and then as questions of their own. That is bounded three ways:
    • At the top only, where such asking reaches.
    • Once. A term asked so is at the top itself, and asking inside it lifted the search again with the depth reset each time. Together with a rule that wrote a + b x as t, x Ei(a + b x)^2 grew a test host to twelve gigabytes; that rule is not in this PR. A decline the once-only flag causes is not cached (Integration.DeclinedForItsScope), as a decline that ran out of depth is not.
    • For a multiple of x only. For a + b x, the remainder divides by the linear, and its terms are the exponentials a hyperbolic function is written as. Asking them took the decline of x Shi(a + b x)^2 from a second to past twenty.

Measured

Input Was (2.5.0) Now
"x*Si(b*x)*sin(b*x)".Integrate("x") a polynomial in a variable Si an antiderivative in Si(b x), Ci(2 b x) and ln(x)
"Ei(b*x)^2".Integrate("x") Ei * (b * x) ^ 3 / 3 / b + C, with Ei a variable an antiderivative in Ei(b x) and Ei(2 b x)
"x*erf(b*x)^2".Integrate("x") UnrecognizedFunctionParseException: there is no function erf an antiderivative in erf(b x)

SpecialFunctionsByPartsTest has six rows beside a power and the elementary factor of the derivative, and eleven squares, each differentiated back with its parameters pinned.

Not in this PR: the squares of a special function of a + b x beside a power of x, about twenty of the 53 left. By parts leaves them over the linear, and they want the polynomial divided by it before the terms are asked. Also F(d (a + b log(c x^n))) (16), and the Gaussian-weighted erf(b x)/(e^(b^2 x^2) x^k) (8).

Part of #1501.

🤖 Generated with Claude Code

…, and so is its square

x Si(b x) sin(b x) was left unevaluated where Si(b x) sin(b x) was not. By parts it is Si(b x)
against x sin(b x), and the integral of that factor was taken with parts off, which x sin(b x)
needs. Beside a special function of a linear argument, a polynomial times something else is
integrated by the polynomial's parts now, which end in as many steps as its degree, and what is
left, the special function's derivative times polynomials and elementary functions, is given parts
in turn.

A square of a special function of b x is two rounds of parts, and the remainder of the first comes
back as one product over a sum, (b x Ei(b x) - e^(b x)) e^(b x)/(b x) for Ei(b x)^2, that no rule
reads whole, where its terms e^(b x) Ei(b x) and e^(2 b x)/(b x) are each answered when asked. So
where the remainder after a special function is not answered, its terms are asked one at a time:
the ordinary way first, and then as questions of their own. That is only at the top, where such
asking reaches. It is done once, since a term asked so is at the top itself, and the same asking
inside it lifted the search again with the depth reset each time: together with a rule that wrote
a + b x as t, x Ei(a + b x)^2 grew a test host to twelve gigabytes. A decline that the once-only
flag caused is not cached (Integration.DeclinedForItsScope), as a decline that ran out of depth is
not. It covers a multiple of x only: of a + b x the remainder divides by the linear, its terms are
the exponentials a hyperbolic function is written as, and the decline of x Shi(a + b x)^2 went from
a second to past twenty asking them.

Rubi's family 8, #1501's tranche of 420: 296 -> 367 solved, 0 wrong, 0 timeout, against master
with #1638. The 71 gains are 0 of 71 on master and 71 of 71 here run alone, and the 53 still
declined take 103 s against 117 s together, median ratio 1.00, the slowest change being
x^2 Ci(a + b x) cos(a + b x), 0.25 s to 2 s. Nothing else moves: the independent suites are 1756 of
1814 and families 1 to 7 at five a file 813 of 912 on both, 0 wrong everywhere, and what is
declined in both costs what it did (11.9 s against 11.5 s, 98.1 s against 98.9 s).

The unit tests pass, 14,247, and the performance gate passes on ee5cb79e, whose tree is this
commit's but for this entry in BREAKING-CHANGES.md: allocation is what the baseline says on all 19
gated benchmarks.

SpecialFunctionsByPartsTest: six rows beside a power and the elementary factor of the derivative,
eleven squares, each differentiated back with its parameters pinned.

Part of #1501.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Rafael-SOWNet Rafael-SOWNet added this to the 2.6.0 milestone Oct 1, 2026
@Rafael-SOWNet
Rafael-SOWNet merged commit 2db4278 into master Oct 1, 2026
31 checks passed
Rafael-SOWNet added a commit that referenced this pull request Oct 1, 2026
… term (#1643)

#1639 asked the remainder of a special function's square term by term only for an argument b x.
For a + b x, the remainder divided by the linear, and its terms were the exponentials a hyperbolic
function is written as, each a harder question than the whole. With the constant of integration
matched to the linear (#1642), the linear cancels and the terms are the case without the offset,
so the asking is offered for any linear argument now. The exception is an error function beside
anything but itself. Its derivative is a Gaussian of the shifted argument rather than a quotient by
it, so a polynomial beside it stays in every term: asking them took the decline of
(c + d x) erf(a + b x)^2 from six seconds to twenty-four, and answered nothing.

Measured on the Rubi corpus, master at 16203aa and this change on it, run side by side: family 8
380 -> 394 of 420, 0 timeout (erf, erfc and erfi of a + b x squared; Si and Ci of a + b x squared
beside x and x^2; Ei, Shi and Chi of a + b x squared beside x^2; Shi(a + b x)^2 and Si(a + b x)^2;
x^2 Ci(a + b x) cos(a + b x) and x^2 cos(a + b x) Si(a + b x)); family 2 544 of 650, the independent
suites 1756 of 1814 and families 1 and 3 to 7 at five a file 800 of 897, on both. 0 wrong
everywhere. Run alone, the fourteen are 0 of 14 on master and 14 of 14 here. Measured the same way
with the error functions not excepted, family 8 was the same 394 with six timeouts more, and
families 0 to 7 moved nowhere. The unit tests pass, 14,265, and the performance gate passes on
ec42a120: allocation is what the baseline says on all 19 gated benchmarks.

SpecialFunctionsByPartsTest has four more rows with a shifted argument, each differentiated back
with its parameters pinned.

Part of #1501.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.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