Skip to content

A symbolic parameter no longer stops a rational integrand being integrated, and 16 more Rubi integrals come out - #1249

Merged
Rafael-SOWNet merged 1 commit into
masterfrom
scaled-variable
Sep 10, 2026
Merged

Rafael-SOWNet merged 1 commit into
masterfrom
scaled-variable

Conversation

@Rafael-SOWNet

Copy link
Copy Markdown
Member

1/(8 + x^3) and 1/(16 - x^4) are answered at once. 1/(a^3 + x^3) and 1/(a^4 - x^4) were not.

The parameter is the whole difference. The rational rules read a denominator as a polynomial over
the rationals
— TryGetRationalCoefficients is the gate — so a^3 is not a coefficient they can
work with, and the factoring that answers x^3 + 8 has nothing to hold on to for x^3 + a^3.

Measured rather than assumed, on master:

ok   1/(8 + x^3)        ok   1/(16 - x^4)
NO   1/(a^3 + x^3)      NO   1/(a^4 - x^4)

Two things were in the way

A constant factor inside the denominator stayed there. The two branches that take a factor out
of a quotient each want the whole of one side free of the variable, so a * (1/(1 + x^3)) was taken
apart and 1/(a*(1 + x^3)), the same number, was not. Taking the constant out now happens first,
before the branch that turns c/g(x) into c * g(x)^(-1) — a power being a shape the rational
rules do not read, that ordering is what decides these.

And the integrand is scaled by its parameter. With x = c t and dx = c dt a homogeneous
integrand becomes a constant times a function of t alone: 1/(a^3 + x^3) becomes
a^(-2)/(1 + t^3), whose denominator has integer coefficients again. The answer is read at
t = x/c.

Homogeneity is checked, and the check is what makes it terminate

The scaled integrand has to divide into a factor free of t times a function of t, and only the
second is handed on — so the sub-problem has one variable and cannot be scaled again. Without that,
the rule would hand on something still carrying c and scale it once more at every level.

x/((a^2 + x^2)*(b^2 + x^2)) is declined for exactly that reason: scaling by one parameter leaves
the other. It is in the tests as a decline, so the check is exercised rather than assumed.

Measured on Rubi's independent test suites

Same corpus and flags, both arms on this machine:

solved wrong timeouts wall clock
2dbeedf7 (master) 913 0 13 722 s
+ this 929 0 16 794 s

Sixteen more answers and no wrong ones, for about 10% more wall clock. Newly answered includes the
whole 1/(x^k (a^n ± x^n)) family, which is where this runs long in Timofeev's set. Each was also
checked by differentiating it back with the parameter pinned and comparing at five points.

Where the answer is not defined

c = 0 is not a scaling, and a^(-2) G(x/a) has no value there. That is the honest report for a
substitution that does not exist rather than a wrong answer — and 1/(a^3 + x^3) at a = 0 is a
different function, 1/x^3, which is answered on its own if asked that way. Recorded in
BREAKING-CHANGES.md rather than left to be discovered.

Ordering

It runs last of the rewrites, because unlike the others it fires on an integrand nothing is
wrong with — it clears a parameter rather than a shape. a*sin(x), a*x^2, a/x, sin(a*x),
x*e^(a*x) and 1/(1 + x^3) are all in the tests to hold that: they were answered before and are
answered by the same rules now.

Suites

UnitTests 8514 and 1557, FSharpWrapperUnitTests 134, InteractiveWrapperUnitTests 18,
TerminalUnitTests 41. New file ScaledVariableIntegralTest.cs, 28 cases.

Part of #718.

🤖 Generated with Claude Code

https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura

…rated, and 16 more Rubi integrals come out

`1/(8 + x^3)` and `1/(16 - x^4)` are answered at once. `1/(a^3 + x^3)` and
`1/(a^4 - x^4)` were not. The parameter is the whole difference: the rational
rules read a denominator as a polynomial over the rationals, and `a^3` is not a
coefficient they can work with, so the factoring that answers `x^3 + 8` has
nothing to hold on to for `x^3 + a^3`.

Two things were in the way and both are fixed here.

A constant factor inside the denominator stayed there. The two branches that
take a factor out of a quotient each want the whole of one side free of the
variable, so `a * (1/(1 + x^3))` was taken apart and `1/(a*(1 + x^3))` -- the
same number -- was not. Taking the constant out now happens first, before the
branch that turns `c/g(x)` into `c * g(x)^(-1)`, because a power is a shape the
rational rules do not read.

And the integrand is scaled by its parameter. With `x = c t` and `dx = c dt` a
homogeneous integrand becomes a constant times a function of `t` alone --
`1/(a^3 + x^3)` becomes `a^(-2)/(1 + t^3)`, whose denominator has integer
coefficients again -- and the answer is read at `t = x/c`.

Homogeneity is checked rather than assumed, and the check is what makes this
terminate. The scaled integrand has to divide into a factor free of `t` times a
function of `t`, and only the second is handed on, so the sub-problem has one
variable and cannot be scaled again. Two parameters is declined for exactly that
reason: scaling by one leaves the other.

Nothing is owed as a condition, and one thing is worth being exact about
instead: `c = 0` is not a scaling, and `a^(-2) G(x/a)` has no value there. That
is the honest report for a substitution that does not exist rather than a wrong
answer, and `1/(a^3 + x^3)` at `a = 0` is a different function which is answered
on its own if asked that way.

It runs last of the rewrites, because unlike the others it fires on an integrand
nothing is wrong with -- it clears a parameter rather than a shape -- so
everything that can answer the problem as written tries first.

Measured on Rubi's independent test suites, same corpus and flags, both arms on
this machine:

    before (2dbeedf)  913/1774, 0 wrong, 13 timeouts, 722s
    after              929/1774, 0 wrong, 16 timeouts, 794s

Sixteen more answers and no wrong ones, for about 10% more wall clock. Each of
the newly answered was also checked by differentiating it back with the
parameter pinned and comparing at five points.

Suites: UnitTests 8514 and 1557, FSharpWrapperUnitTests 134,
InteractiveWrapperUnitTests 18, TerminalUnitTests 41.

#718

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura
@Rafael-SOWNet

Copy link
Copy Markdown
Member Author

Merge order against the other two open ones. This does not conflict with #1245 at all. It conflicts with #1248 in two places — the end of IndefiniteIntegralSolver.cs and Sources/.editorconfig — and both are additive: keep both blocks, in either order.

Composed on a throwaway branch to check they do more than merge, since #1248 changes how partial fractions reads a quotient and this changes the order in which a factor comes out of one:

UnitTests (Calculus)     1570 passed
FSharpWrapperUnitTests    134 passed

Whichever you take second I will rebase.

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