An exponential or a hyperbolic function over several linears is split into partial fractions - #1640
Merged
Merged
Conversation
… into partial fractions e^x/(x (x + 1)) was left unevaluated, where e^x/x and e^x/(x + 1) were each answered with the exponential integral. The rule for an exponential of a linear over a power of a linear read one linear below the bar, and the rule for sinh and cosh, which arrive as sums of exponentials, did the same. The rule for a sine or a cosine already split a quotient over several linears into partial fractions, each term the one-linear question; the exponential and hyperbolic ones do too now, through PartialFractions.TrySplitOverWrittenFactors, which reads symbolic coefficients and checks the split at pinned points before it is used. e^x/(x (x + 1)) is Ei(x) - Ei(x + 1)/e. It is also what by parts leaves of Ei(a + b x)/x^2: e^(a + b x)/((a + b x) x). The polynomial part comes off by long division only where the fraction is not proper already. The rule for a sine or a cosine divided every time, and x over (c + d x)(x - 2) came back as a quotient and a remainder 2 provided not c + d x = 0, which nothing splits: x sin(x)/((c + d x)(x - 2)) was declined where x sin(x)/((x + 3)(x - 2)) was answered. Both rules divide only an improper fraction now. Measured on the Rubi corpus, master at 9193d97 and this change on it, run side by side: family 8 296 -> 302 of 420 (Ei, Shi and Chi of a + b x over x^2 and over x^3), family 6 at twenty a file 412 -> 414 of 472 (cosh(c + d x)/(x (a + b x)) and over x^3 (a + b x)^3), family 2 543 of 650 on both, the independent suites 1756 of 1814 and families 1, 3, 4, 5 and 7 at five a file 682 of 768 on both. 0 wrong everywhere. Run alone, the eight are 0 of 8 on master and 8 of 8 here. The unit tests pass, 14,240, also with the GC heap held to 4 GB, and the performance gate passes on 3b94625d, which is this change on 9193d97: allocation is what the baseline says on all 19 gated benchmarks. ExponentialIntegralIntegrationTest and HyperbolicIntegralIntegrationTest have a row set each over several linears, and TrigonometricIntegralIntegrationTest two rows over symbolic ones, 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.
e^x/(x (x + 1))was left unevaluated, wheree^x/xande^x/(x + 1)were each answered with the exponential integral.sinhandcosh, which arrive as sums of exponentials, did the same. The rule for a sine or a cosine already split a quotient over several linears into partial fractions, each term the one-linear question. The exponential and hyperbolic ones do too now, throughPartialFractions.TrySplitOverWrittenFactors. It reads symbolic coefficients and checks the split at pinned points before it is used.e^x/(x (x + 1))isEi(x) - Ei(x + 1)/e. It is also what by parts leaves ofEi(a + b x)/x^2:e^(a + b x)/((a + b x) x).xover(c + d x)(x - 2)then came back as a quotient and a remainder,2 provided not c + d x = 0, which nothing splits. Sox sin(x)/((c + d x)(x - 2))was declined, wherex sin(x)/((x + 3)(x - 2))was answered. Both rules divide only an improper fraction now.Measured
"e^x/(x*(x+1))".Integrate("x")integral(e ^ x / (x * (x + 1)), x)Ei(x) + -1 / e * Ei(x + 1) + C"sinh(x)/(x*(x+1))".Integrate("x")integral((e ^ x - e ^ (-x)) / 2 / (x * (x + 1)), x)1/2 * (2 * Shi(x) + ((-1) / e + e) * Chi(x + 1) + ((-1) / e - e) * Shi(x + 1)) + C"x^3*e^(2*x)/((x+1)*(x-2))".Integrate("x")integral(x ^ 3 * e ^ (2 * x) / ((x + 1) * (x - 2)), x)e ^ (2 * x) * (-1/4 + 1/2 * x) + e ^ (2 * x) / 2 + 1/3 * e ^ (-2) * Ei(2 * (x + 1)) + 8/3 * e ^ 4 * Ei(2 * (x - 2)) + C"x*sin(x)/((c+d*x)*(x-2))".Integrate("x")integral(x * sin(x) / ((c + d * x) * (x - 2)), x)SiandCiof(c + d x)/dandx - 29193d973and this change on it, run side by side, 0 wrong everywhere:Ei,ShiandChiofa + b xoverx^2and overx^3.cosh(c + d x)/(x (a + b x))and the same overx^3 (a + b x)^3.DOTNET_GCHeapHardLimit). The suite's host peaked between 4.4 and 9.1 GB over four unconstrained runs, where master's peaked between 3.1 and 5.8. Under the cap, both suites pass in full, so that is the collector growing the heap while memory is free, not memory the tests need.3b94625d, which is this change on9193d973. Allocation matches the baseline on all 19 gated benchmarks.ExponentialIntegralIntegrationTestandHyperbolicIntegralIntegrationTesteach have a row set over several linears, andTrigonometricIntegralIntegrationTesthas two rows over symbolic ones. Each is differentiated back with its parameters pinned.Part of #1501.
🤖 Generated with Claude Code