Skip to content

The special functions are substitutions, and powers of one base gather across the bar - #1638

Merged
Rafael-SOWNet merged 1 commit into
masterfrom
the-special-functions-are-substitutions
Sep 30, 2026
Merged

Rafael-SOWNet merged 1 commit into
masterfrom
the-special-functions-are-substitutions

Conversation

@Rafael-SOWNet

Copy link
Copy Markdown
Member

None of the nine special functions was a candidate for the substitution u = g(x). So an integrand that is a power of one beside its derivative had no route, and these were left unevaluated:

  • e^(c - b^2 x^2) erf(b x)^n
  • Ei(b x) e^(b x)/x
  • Si(b x) sin(b x)/x

Each special function is a candidate now, as the logarithm is, and its elementary derivative is the differential: e^(c - b^2 x^2) erf(b x) is sqrt(pi) e^c/(2b) u du under u = erf(b x).

  • A constant in the exponent still stopped it. Divided by du/dx, e^(c - b^2 x^2) over the e^(-(b x)^2) of the derivative is e^c. The quotient was simplified only a level, so the x in it was left and the candidate refused, where e^(-b^2 x^2) erf(b x) was answered. The divisor's factors are now spread to the power -1, the powers of one base gathered, and the result simplified a level, which is where e^(c - (b x)^2 + (b x)^2) becomes e^c.
  • Offered only where its derivative can be the differential. That means an exponential of a quadratic for the error functions, and a logarithm below the bar for li. For the others, whose derivatives divide by their argument, it means something in x below the bar. Offered beside anything, x cosh(a + b x) Shi(a + b x) went from a second to ten, simplifying quotients of exponentials that were never going to lose their x.
  • Gathered only for a special-function candidate. Done for every candidate that left an x, it gathered and simplified the exponentials of 1/((c + d x)^3 (a + a tanh(e + f x))) once for each candidate. Seven declines of a third of a second became timeouts.

The nine functions were listed three times in the solver, so they are listed once now, in IsASpecialFunction.

Measured

Input Was (2.5.0) Now
"e^(c - b^2*x^2)*erf(b*x)".Integrate("x") UnrecognizedFunctionParseException: there is no function erf e ^ c * pi ^ (1/2) * erf(b * x) ^ 2 / 2 / (2 * b) + C
"e^(b*x)*Ei(b*x)/x".Integrate("x") Ei * e ^ (b * x) + C, with Ei a variable Ei(b * x) ^ 2 / 2 + C
"Si(b*x)*sin(b*x)/x".Integrate("x") Si * -cos(b * x) + C, with Si a variable Si(b * x) ^ 2 / 2 + C

SpecialFunctionSubstitutionTest has nine rows from Rubi's 8.1, 8.3 and 8.4, each differentiated back with its parameters pinned.

Part of #1501.

🤖 Generated with Claude Code

…r across the bar

None of the nine special functions was a candidate for the substitution u = g(x), so an integrand
that is a power of one beside its derivative had no route: e^(c - b^2 x^2) erf(b x)^n,
Ei(b x) e^(b x)/x and Si(b x) sin(b x)/x were left unevaluated. Each is a candidate now, as the
logarithm is, and its elementary derivative is the differential: e^(c - b^2 x^2) erf(b x) is
sqrt(pi) e^c/(2b) u du under u = erf(b x).

A constant in the exponent still stopped it: divided by du/dx, e^(c - b^2 x^2) over the
e^(-(b x)^2) of the derivative is e^c, and the quotient is simplified only a level, so the x in it
was left and the candidate refused, where e^(-b^2 x^2) erf(b x) was answered. The divisor's factors
are spread to the power -1 now, the powers of one base gathered, and the result simplified a level,
which is where e^(c - (b x)^2 + (b x)^2) becomes e^c.

Both only where they can answer. A special function is offered only where its derivative can be
the differential: an exponential of a quadratic for the error functions, a logarithm below the bar
for li, and something in x below the bar for the others, whose derivatives divide by their
argument. Offered beside anything, x cosh(a + b x) Shi(a + b x) went from a second to ten,
simplifying quotients of exponentials that were never going to lose their x. And the powers are
gathered only for a special-function candidate: done for every candidate that left an x, the
exponentials of 1/((c + d x)^3 (a + a tanh(e + f x))) were gathered and simplified for each one,
and seven declines of a third of a second became timeouts. The nine are listed once, in
IsASpecialFunction, where the solver listed them three times.

Rubi's family 8, #1501's tranche of 420: 258 -> 296 solved, 0 wrong, against master at ad05a79.

Nothing without a special function moves. The independent suites are 1753 of 1814 on both; families
1 to 7 at five problems a file are 809 and 811 of 912 run side by side, and the two that moved,
3.2.1 #12 and 6.7.1 #180, are answered alone by both, in 18 and 22 s: master's timeouts there were
the load. 0 wrong everywhere.

SpecialFunctionSubstitutionTest has nine rows from Rubi's 8.1, 8.3 and 8.4, 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 Sep 30, 2026
@Rafael-SOWNet
Rafael-SOWNet merged commit 9193d97 into master Sep 30, 2026
31 checks passed
Rafael-SOWNet added a commit that referenced this pull request Oct 1, 2026
…, and so is its square (#1639)

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