Repository navigation
An improper quotient is divided out before it is decomposed (#180) - #1147
Merged
Merged
Conversation
Every step of the rational integrator wants a proper fraction, and each of the three declines an improper one rather than dividing it out. So `x^2/(x + 1)` had no antiderivative, although it is `x - 1 + 1/(x + 1)` and every piece of that has been integrable throughout. The division is not new code. `TreeAnalyzer.PolynomialLongDivision` has done it all along for the simplifier's own rule set of that name; the integrator never asked it. What changes is one call, placed before the three decompositions rather than after them. New as written: `x^2/(x + 1)`, `x^3/(1 + x^2)`, `x^4/(x^2 + 1)`, `(x^5 + 2)/(x^2 + 1)`, `(x^2 + 3x + 5)/(x + 2)`, and the exact divisions `(x^3 + 1)/(x + 1)` and `(x^2 - 1)/(x - 1)` whose proper part is zero. New through a substitution, which is where it matters more, since there the improper fraction is produced rather than written: `tan(x)^2`, `tan(x)^3` and `sqrt(x)/(x + 1)`. All three were on the declined lists added earlier today, each naming this gap as its reason, and all three failed those tests when this landed -- which is what a recorded boundary is for. A proper fraction is untouched: the helper answers nothing for one, so the steps below see what they saw before. A symbolic leading coefficient is still declined, and this corrects what I said on #180. Item 18 there is `x^2/(a + b*x)`, which I expected to come with this and does not: the division would divide by `b`, which is not decidably non-zero, and at `b = 0` the quotient is `x^2/a`, whose antiderivative is not the limit of the divided form. `x^2/(x + a)` is declined too, for the narrower reason that the helper does not divide a polynomial whose other coefficients are symbolic. Both are pinned by a test. Full suite 9356 passed, 0 failed. Part of #180. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura
16 tasks done
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.
Every step of the rational integrator wants a proper fraction — a numerator of lower
degree than the denominator — and each of the three declines an improper one rather than
dividing it out. So
x^2/(x + 1)had no antiderivative, although it isx - 1 + 1/(x + 1)and every piece of that has been integrable throughout.
The division was already written
TreeAnalyzer.PolynomialLongDivisionhas done this all along, for the simplifier's ownPolynomialLongDivisionrule set. The integrator never asked it. The diff to the library isone call, placed before the three decompositions rather than after them — no new algorithm,
and nothing about the division itself changed.
That is worth saying plainly because the gap read like a missing capability from the outside:
three separate places in the code say an improper fraction "has to be divided out first, which
is not done here", and the thing they describe existed one namespace away.
What it delivers
As written:
x^2/(x + 1)x^2/2 - x + ln(x + 1) + Cx^3/(1 + x^2)x^4/(x^2 + 1)(x^5 + 2)/(x^2 + 1)(x^2 + 3x + 5)/(x + 2)(x^3 + 1)/(x + 1),(x^2 - 1)/(x - 1)Through a substitution, which is where it matters more, because there the improper fraction is
produced rather than written by anyone:
tan(x)^2u^2/(1 + u^2)tan(x) - arctan(tan(x)) + Ctan(x)^3u^3/(1 + u^2)sqrt(x)/(x + 1)2u^2/(1 + u^2)int tan(x)^2comes back astan(x) - arctan(tan(x)) + Crather than the textbooktan(x) - x. Those are the same function on the principal branch, and the second is what therewrite would have to assert about which branch
xis on, so the first is the honest form.The declined lists caught this, which is what they are for
All three of
tan(x)^2,tan(x)^3andsqrt(x)/(x + 1)were on "what is still declined"theories added earlier today, each naming the improper-fraction gap as its reason. All three
failed the moment this landed, and moved to the positive cases with a note saying where they
came from. A boundary recorded as a test fails when the boundary moves; recorded as prose it
just goes quietly wrong.
What is still declined
A proper fraction is untouched — the helper answers nothing for one, so the three steps
below it see exactly what they saw before.
int 1/(x + 1)is stillln(x + 1) + Candint x/(x^2 + 1)stillln(x^2 + 1)/2 + C, both asserted.A symbolic leading coefficient, and this corrects something I wrote on #180 earlier today.
Item 18 there is
x^2/(a + b*x), which I said should come with this work. It does not: thedivision would have to divide by
b, which is not decidably non-zero, and atb = 0thequotient is
x^2/a, whose antiderivative is not the limit of the divided form.x^2/(x + a)is declined too, for the narrower reason that the helper does not divide a polynomial whose
other coefficients are symbolic even when the leading one is
1. Both are pinned by a test,and I will correct the comment on #180.
Handling either would want the
Piecewise-on-the-degenerate-case treatment thatIntegrateRationalQuadraticalready uses fora = 0, which is its own change with its ownsoundness argument.
Verification
Full suite 9356 passed, 0 failed, 14 skipped. Corpus still 40 of 40.
Every new answer is checked by differentiating it back and comparing at sampled points, through
a helper that first asserts the antiderivative contains no
integral(— without that guard thecheck passes vacuously, since
d/dxof an unevaluatedintegral(f, x)isf.Part of #180.