A rational integral over the roots of its denominator - #1637
Merged
Rafael-SOWNet merged 1 commit intoSep 30, 2026
Merged
Conversation
The Rothstein-Trager resultant declined a rational function whose residues lie in a field of degree above two: 1/(x^3 + x + 1) and #1285's sqrt(x)/(1 + x + x^4), 2u^2/(1 + u^2 + u^8) under u = sqrt(x), were left unevaluated. Their logarithms are written now as a sum over the roots of the factor of the denominator they belong to, sum(A(r)/D'(r) ln(x - r), r in { r : E(r) = 0 }), the form #1285 asked for, with the node #1624 added. The poles whose residues are roots of R are the common roots of D and D'^n R(A/D'), so E is their gcd over the rationals, and no arithmetic in the residues' field is needed. Only as a last resort. Asked beside the other rules, the sum answered each of Jeffrey's three terms of (-1 + 4 cos(x) + 5 cos(x)^2)/(-1 - 4 cos(x) - 3 cos(x)^2 + 4 cos(x)^3) with a sum over the roots of a sextic, where the whole is 2 arctan(tan(x/2)^3 - 2 tan(x/2)). So the rule declines as before and notes that a sum would answer, and only where the question comes back unanswered and that was noted is it asked again with sums allowed, under a memo of its own; the answer found then is remembered for the question. The integrator checks an answer in double intervals and then in decimals, and neither read the sum node, so every such answer would have been declined by its own check. PreciseEvaluation encloses each root now: Durand-Kerner's approximations, each widened by its Weierstrass correction in intervals, n |w_k| about z_k, which holds exactly one root where the rectangles are apart (Braess and Hadeler), and the summand worked out on each rectangle. Measured on the Rubi corpus, master at ad05a79 and this change on it, run side by side: the independent suites 1753 -> 1756 of 1814 (Bondarenko 22 and 23, and Hearn 66, 1/(1 - x^4 + x^8)); family 1 at ten problems a file, 295 -> 301 of 377 (1/(x^2 (1 - x^3 + x^6)), (1 + x^4)/(1 - x^4 + x^8), (1 + x^4)/(1 - 5x^4 + x^8), (-1 + 2x^4 + sqrt(3))/(1 - x^4 + x^8), (1 - x^4)/(1 - x^4 + x^8) and x^3 (5 + x + 3x^2 + 2x^3)/(2 + x + 5x^2 + x^3 + 2x^4)); families 2 to 7 at the usual sample, 663 of 722 on both. 0 wrong everywhere. Run alone, those nine are 0 of 9 on master and 9 of 9 here, and the tenth problem that moved, 1.1.4.3 #231, is 17.9 s unevaluated on both: its master timeout was the load of the side-by-side run. A question still declined costs what it did: the problems unevaluated in both arms took 14.2 s against 13.4 s in the independent suites, 65.6 s against 64.7 s in families 2 to 7 and 89.9 s against 92.3 s in the family 1 sample. The performance gate passes on 34c548a8, whose library code is this commit's: allocation is what the baseline says on all 19 gated benchmarks. RothsteinTragerTest: the cubic, quartic and quintic rows that were pinned as declined are sums now, and #1285's integral in PowerSubstitutionIntegralTest; that test's declined witnesses are the elliptic x^2/sqrt(x^4 + x + 1) and x^2/sqrt(x^4 + x^3 + 1), which nothing answers. BinomialDenominatorIntegralTest, PartialFractionsTest and RationalIntegralsTest pinned 1/(x^3 + x + 1), 1/(x^3 + x^2 + x + 2), 1/(x^4 + x + 1) and 1/(x^4 + x^3 + 1) as declined: each is the sum now, checked by differentiating back, and the boundary pinned in their place is the same kind of denominator with a symbol among its coefficients, which the sum is not written for. DecliningStaysCheap keeps its ten-second bound as FindingThatNothingSplitsStaysCheap: the second pass starts only once the first has declined, so the decline it guards is still inside the bound. Part of #1285. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rafael-SOWNet
added a commit
that referenced
this pull request
Sep 30, 2026
…r across the bar (#1638) 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. The unit tests pass on master with #1637, 14,230, and the performance gate passes on fd1a4416, which is this change on ad05a79: allocation is what the baseline says on all 19 gated benchmarks. 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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The rational integrator declined a rational function whose residues lie in a field of degree three or more.
1/(x^3 + x + 1)was left unevaluated, and so was #1285'ssqrt(x)/(1 + x + x^4), which is2u^2/(1 + u^2 + u^8)underu = sqrt(x). Their logarithms are written now as a sum over the poles they belong to, the form #1285 asked for, with the node from #1624:sum(A(r)/D'(r) ln(x - r), r in { r : E(r) = 0 })Rare the common roots ofDandD'^n R(A/D'), soEis their gcd over the rationals. No arithmetic in the residues' field is needed. Residues that are rational or roots of a quadratic keep the logarithms and arctangents they had.(-1 + 4 cos(x) + 5 cos(x)^2)/(-1 - 4 cos(x) - 3 cos(x)^2 + 4 cos(x)^3)with a sum over the roots of a sextic, where the whole is2 arctan(tan(x/2)^3 - 2 tan(x/2)). So the rule declines as before and notes that a sum would answer. Only when the whole question comes back unanswered, with that noted, is it asked again with sums allowed, under a memo of its own. The answer found then is remembered for the question.PreciseEvaluationencloses each root now. It takes Durand–Kerner's approximations and widens each by its Weierstrass correction,n |w_k|aboutz_k. Where those rectangles are apart, each holds exactly one root (Braess and Hadeler), and the summand is worked out on each rectangle.Measured
"1/(x^3 + x + 1)".Integrate("x")integral(1 / (x ^ 3 + x + 1), x)sum(1 / (3 * r ^ 2 + 1) * ln(x - r), r in { r : r ^ 3 + r + 1 = 0 }) + C"sqrt(x)/(1 + x + x^4)".Integrate("x")integral(sqrt(x) / (1 + x + x ^ 4), x)sum(2 * r ^ 2 / (8 * r ^ 7 + 2 * r) * ln(x ^ (1/2) - r), r in { r : r ^ 8 + r ^ 2 + 1 = 0 }) + C"1/(1 - x^4 + x^8)".Integrate("x")integral(1 / (1 - x ^ 4 + x ^ 8), x)sum(1 / (8 * r ^ 7 + (-4) * r ^ 3) * ln(x - r), r in { r : r ^ 8 + -r ^ 4 + 1 = 0 }) + C"1/(x^4 + a*x + 1)".Integrate("x")integral(1 / (x ^ 4 + a * x + 1), x)Jeffrey's integrand is
2 arctan(tan(x/2)^3 - 2 tan(x/2))on master and here. Every answer above differentiates back to its integrand at six points.ad05a79band this change on it, run side by side, 0 wrong everywhere:1/(1 - x^4 + x^8).1/(x^2 (1 - x^3 + x^6)), four quotients over1 - x^4 + x^8and1 - 5x^4 + x^8, and 1.3.1 Update actions #361.34c548a8, whose library code is this head's. Allocation matches the baseline on all 19 gated benchmarks.Tests whose pins moved
BinomialDenominatorIntegralTest,PartialFractionsTestandRationalIntegralsTestpinned four denominators as declined:1/(x^3 + x + 1),1/(x^3 + x^2 + x + 2),1/(x^4 + x + 1)and1/(x^4 + x^3 + 1). Each is now the sum, checked by differentiating it back. The boundary pinned in their place is1/(x^4 + a x + 1)and1/(x^3 + x + a).DecliningStaysCheapkeeps its ten-second bound, renamedFindingThatNothingSplitsStaysCheap. The second pass starts only once the first has declined, so the decline it guards is still inside the bound.Closes #1285.
🤖 Generated with Claude Code