Skip to content

Commit 790feec

Browse files
Take powers of linears apart beside a symbolic root of a quadratic (#1881)
* Take powers of linears apart beside a symbolic root of a quadratic Over linears alone the split left the integrand to Euler's substitution, which writes the root of a symbolic leading coefficient into every coefficient and declined sqrt(a + b x + c x^2)/(x^2 (d + e x)). With a symbol in the integrand it is taken apart, and Rubi 1.2.2.4's sqrt(a + b x^2 + c x^4)/(x^3 (d + e x^2)) is one under u = x^2. Part of #718 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura * Pin a symbol, not Euler's number, in the split's test Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura * Record the answers the split over powers of linears gives Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent 397aa97 commit 790feec

3 files changed

Lines changed: 101 additions & 2 deletions

File tree

‎BREAKING-CHANGES.md‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,30 @@ same answer as on the unreleased master, in 1.4 seconds rather than 30
555555
| `"1/((d + k*x)*(f + g*x)*(a + b*x + c*x^2)^2)".ToEntity().Integrate("x")` | `integral(...)` | 24,143 characters |
556556
| `"1/((d + k*x)^3*(a + b*x + c*x^2)^2)".ToEntity().Integrate("x")` | `integral(...)` | 9,593 characters |
557557

558+
### Powers of linears beside a symbolic root of a quadratic are taken apart over the linears
559+
560+
**Answers where there were none.** `sqrt(a + b x + c x^2)/((d + k x)(f + g x)^2)` was declined: with no quadratic
561+
below the bar, powers of linears were left to Euler's substitution, which writes the root of a symbolic leading
562+
coefficient into every coefficient and does not finish. They are taken apart over the linears now where the
563+
integrand has a symbol in it, each piece closed beside the root. The answers are large because each piece's cases,
564+
by the sign of the radicand at its pole and of `c`, multiply in the sum
565+
([#1874](https://github.com/asc-community/AngouriMath/issues/1874)): the fourth row is 27 cases of about 3,000
566+
characters each ([#718](https://github.com/asc-community/AngouriMath/issues/718)).
567+
568+
| Input | Was (2.5.0) | Now |
569+
|---|---|---|
570+
| `"sqrt(a + b*x + c*x^2)/((d + k*x)*(f + g*x)^2)".ToEntity().Integrate("x")` | `integral(...)` | 12,694 characters |
571+
| `"sqrt(a + b*x + c*x^2)/((d + k*x)*(f + g*x)^3)".ToEntity().Integrate("x")` | `integral(...)` | 20,029 characters |
572+
| `"sqrt(a + b*x + c*x^2)/((d + k*x)*(f + g*x)^4)".ToEntity().Integrate("x")` | `integral(...)` | 29,203 characters |
573+
| `"(a + b*x + c*x^2)^(3/2)/((d + k*x)*(f + g*x)^3)".ToEntity().Integrate("x")` | `integral(...)` | 79,744 characters |
574+
| `"1/((d + k*x)*(f + g*x)^2*sqrt(a + b*x + c*x^2))".ToEntity().Integrate("x")` | `integral(...)` | 11,335 characters |
575+
| `"1/((d + k*x)*(f + g*x)^3*sqrt(a + b*x + c*x^2))".ToEntity().Integrate("x")` | `integral(...)` | 18,103 characters |
576+
| `"sqrt(a + b*x^2 + c*x^4)/(x^3*(d + k*x^2))".ToEntity().Integrate("x")` | `integral(...)` | 5,902 characters |
577+
| `"(a + b*x^2 + c*x^4)^(3/2)/(x^3*(d + k*x^2))".ToEntity().Integrate("x")` | `integral(...)` | 27,184 characters |
578+
| `"1/(x^3*(d + k*x^2)*sqrt(a + b*x^2 + c*x^4))".ToEntity().Integrate("x")` | `integral(...)` | 5,515 characters |
579+
| `"asec(a + b*x)/x^4".ToEntity().Integrate("x")` | `integral(...)` | 11,873 characters |
580+
| `"acsc(a + b*x)/x^4".ToEntity().Integrate("x")` | `integral(...)` | 11,864 characters |
581+
558582
### A trinomial the numerator holds is divided out of a power of it
559583

560584
**A shorter answer, where 2.5.0 had none.** `(d + g x + f x^2)(a + b x^2 + c x^4)/(a + b x^2 + c x^4)^4`, written

‎Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18636,8 +18636,10 @@ static Entity WithoutConditions(Entity coefficient)
1863618636
// the linears alone the reciprocal writes a sign of each, `sgn(sqrt(1 + x) - 1)` once
1863718637
// `sqrt(x + sqrt(1 + x))/x^2` is taken back from `u = sqrt(1 + x)`, whose derivative
1863818638
// is not read where the argument is not shown real -- and Euler's substitution, after
18639-
// this, answers those without one.
18640-
if (beyondTheLinears && !aQuadratic)
18639+
// this, answers those without one. With a symbol in them it does not: the leading
18640+
// coefficient's root is in every coefficient it writes, and `sqrt(a + b x + c x^2)/(x^2 (d + e x))`,
18641+
// which is Rubi's 1.2.2.4 under `u = x^2`, was declined.
18642+
if (beyondTheLinears && !aQuadratic && !expr.Vars.Any(symbol => symbol != x))
1864118643
return null;
1864218644
// Distinct: two factors with the same root are one repeated, which is not this.
1864318645
// Beyond the linears the split decides that, and merges linears with one root.
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//
2+
// Copyright (c) 2019-2026 Angouri.
3+
// AngouriMath is licensed under MIT.
4+
// Details: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.
5+
// Website: https://am.angouri.org.
6+
//
7+
8+
using System;
9+
using AngouriMath.Extensions;
10+
using Xunit;
11+
12+
namespace AngouriMath.Tests.Calculus
13+
{
14+
/// <summary>
15+
/// A rational function with powers of linears below the bar, beside a half-odd power of a
16+
/// quadratic with symbols in it, taken apart over the linears: Euler's substitution, which
17+
/// the split left these to, writes the root of a symbolic leading coefficient into every
18+
/// coefficient. Rubi's 1.2.2.4 <c>sqrt(a + b x^2 + c x^4)/(x^3 (d + e x^2))</c> is one under
19+
/// <c>u = x^2</c>, written here with <c>k</c> for <c>e</c>, which is Euler's number.
20+
/// <a href="https://github.com/asc-community/AngouriMath/issues/718">#718</a>
21+
/// </summary>
22+
[Trait("Area", "Calculus")]
23+
public sealed class PowersOfLinearsBesideASymbolicRootIntegralTest
24+
{
25+
private static void DifferentiatesBack(string integrand, double[] points, params (string, double)[] pins)
26+
{
27+
var integral = integrand.ToEntity().Integrate("x");
28+
Assert.DoesNotContain("integral(", integral.Stringize());
29+
Assert.DoesNotContain("NaN", integral.Stringize());
30+
31+
// Pinned before it is differentiated: the answer carries `sgn(x + d/k)`, whose
32+
// derivative is read where its argument is a number.
33+
var pinned = integral.Substitute("C", 0);
34+
Entity original = integrand.ToEntity();
35+
foreach (var (name, value) in pins)
36+
{
37+
pinned = pinned.Substitute(name, value);
38+
original = original.Substitute(name, value);
39+
}
40+
var derivative = pinned.Differentiate("x");
41+
42+
var compared = 0;
43+
foreach (var at in points)
44+
{
45+
var got = derivative.Substitute("x", at).EvalNumerical();
46+
var want = original.Substitute("x", at).EvalNumerical();
47+
if (got.IsNaN || want.IsNaN)
48+
continue;
49+
compared++;
50+
var difference = Math.Abs((double)(got - want).RealPart)
51+
+ Math.Abs((double)(got - want).ImaginaryPart);
52+
var scale = Math.Max(1.0, Math.Abs((double)want.RealPart) + Math.Abs((double)want.ImaginaryPart));
53+
Assert.True(difference / scale < 1e-8,
54+
$"d/dx of the antiderivative of {integrand} is {got} at x = {at}, "
55+
+ $"where the integrand is {want}");
56+
}
57+
Assert.True(compared >= 3,
58+
$"only {compared} of {points.Length} points were comparable for {integrand}");
59+
}
60+
61+
[Theory]
62+
[InlineData("sqrt(a+b*x+c*x^2)/(x^2*(d+k*x))")]
63+
[InlineData("1/(x^2*(d+k*x)*sqrt(a+b*x+c*x^2))")]
64+
[InlineData("sqrt(a+b*x^2+c*x^4)/(x^3*(d+k*x^2))")]
65+
[InlineData("1/((d+k*x)*(f+g*x)^2*sqrt(a+b*x+c*x^2))")]
66+
public void IsAnsweredAndDifferentiatesBack(string integrand)
67+
{
68+
var points = new[] { -1.4, -0.3, 0.8, 2.25 };
69+
DifferentiatesBack(integrand, points, ("a", 2), ("b", 1.0 / 3), ("c", 1.5), ("d", 1.25), ("k", 3), ("f", 7.0 / 3), ("g", -0.4));
70+
DifferentiatesBack(integrand, points, ("a", -1), ("b", 3), ("c", 2), ("d", -2), ("k", 1.5), ("f", 0.5), ("g", 5.0 / 3));
71+
}
72+
}
73+
}

0 commit comments

Comments
 (0)