Skip to content

Commit a41415b

Browse files
A power of x below the bar beside a root of a binomial is rationalised by dividing by the root (#1849)
* A power of x below the bar beside a root of a binomial is rationalised by dividing by the root Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura * Re-measure an entry row on the merged master 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 a15d60e commit a41415b

3 files changed

Lines changed: 83 additions & 5 deletions

File tree

‎BREAKING-CHANGES.md‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,24 @@ back after. Each answer is in three cases by the sign of `4 a/c - (b/c)^2`
194194
| `"x^5/(a + b*x + c*x^2)^5".ToEntity().Integrate("x")` | `integral(...)` | 4,066 characters |
195195
| `"x^7/(a + b*x + c*x^2)^5".ToEntity().Integrate("x")` | `integral(...)` | 5,602 characters |
196196

197+
### A power of x below the bar beside a root of a binomial is rationalised by dividing by the root
198+
199+
**Answers where there were none.** `(a + b x^3)^(1/3)/(x^2 (c + d x^3))` was declined, and so were sixteen more of Rubi's
200+
1.1.3.4 with `x^2`, `x^5`, `x^8`, `x^11` or `x^14` below the bar beside `(a + b x^3)^(1/3)`, `^(4/3)` or `^(-2/3)`.
201+
`u = x/(a + b x^3)^(1/3)` makes each rational, and was used where the power of x stood above the bar only:
202+
`x^(-2)` is `x` times `x^(-3)`, and the second is a function of `x^3` like the rest
203+
([#718](https://github.com/asc-community/AngouriMath/issues/718)).
204+
205+
| Input | Was (2.5.0) | Now |
206+
|---|---|---|
207+
| `"(a + b*x^3)^(1/3)/(x^2*(c + d*x^3))".ToEntity().Integrate("x")` | `integral(...)` | 857 characters |
208+
| `"(a + b*x^3)^(1/3)/(x^11*(c + d*x^3))".ToEntity().Integrate("x")` | `integral(...)` | 4,974 characters |
209+
| `"(a + b*x^3)^(4/3)/(x^2*(c + d*x^3))".ToEntity().Integrate("x")` | `integral(...)` | 1,562 characters |
210+
| `"(a + b*x^3)^(4/3)/(x^14*(c + d*x^3))".ToEntity().Integrate("x")` | `integral(...)` | 6,092 characters |
211+
| `"1/(x^2*(a + b*x^3)^(2/3)*(c + d*x^3))".ToEntity().Integrate("x")` | `integral(...)` | 1,586 characters |
212+
| `"(a + b*x^3)^(1/3)/(x^2*(a*d - b*d*x^3))".ToEntity().Integrate("x")` | `integral(...)` | 773 characters |
213+
| `"1/(x^2*(1 - x^3)^(2/3)*(1 + x^3))".ToEntity().Integrate("x")` | `integral(...)` | 471 characters |
214+
197215
### `a + i a tan` beside the tangent's differential is lowered over its conjugate
198216

199217
**Answers where there were none.** `sqrt(a + i a tan(x))/(c + d tan(x))^(3/2)` ran past thirty seconds:

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

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5528,7 +5528,10 @@ Entity Carried(int numerator, int denominator, int nextSine, int nextCosine)
55285528
/// <c>u^j</c> times the same in <c>u</c>, since <c>x^j (c + d x^n)^(-j/n)</c> is
55295529
/// <c>u^j</c>. Rubi's 1.1.3.4: <c>x/((a + b x^3)^(2/3) (c + d x^3))</c> is
55305530
/// <c>u/(c - (b c - a d) u^3)</c>, and <c>x^4 (a + b x^3)^(1/3)/(c + d x^3)</c> is the
5531-
/// same with <c>x^3</c> beside it; each was declined.
5531+
/// same with <c>x^3</c> beside it; each was declined. A power of x below the bar is read
5532+
/// the same way, with the multiple of <c>n</c> it leaves going into the rational function:
5533+
/// <c>(a + b x^3)^(1/3)/(x^2 (c + d x^3))</c> is <c>x</c> times <c>1/(x^3 (c + d x^3))</c>
5534+
/// times <c>(a + b x^3)^(1 - 2/3)</c>, Rubi's 1.1.3.4:763.
55325535
/// </para>
55335536
/// https://github.com/asc-community/AngouriMath/issues/718
55345537
/// </remarks>
@@ -5577,20 +5580,30 @@ Entity Carried(int numerator, int denominator, int nextSine, int nextCosine)
55775580
// stand-in for x^n where every power of x is a multiple of n, and declined otherwise.
55785581
if (j != 0)
55795582
{
5580-
// Out of the polynomial above the bar, each of whose powers is then a multiple of n.
5583+
// Out of the polynomial above the bar together with the power of x below it, each
5584+
// power then a multiple of n, below zero too: `x^(-2)` is `x` times `x^(-3)`.
55815585
var (restAbove, restBelow) = Functions.SingleQuotient.Of(rest);
55825586
if (!TreeAnalyzer.TryGetPolynomial(restAbove, x, out var aboveTerms) || aboveTerms.Count == 0)
55835587
return null;
5588+
var belowX = 0;
5589+
Entity belowOtherwise = Number.Integer.One;
5590+
foreach (var factor in Mulf.LinearChildren(restBelow))
5591+
if (factor == x)
5592+
belowX++;
5593+
else if (factor is Powf(var xAgain, Number.Integer power) && xAgain == x && power.EInteger.Sign > 0 && power.EInteger.CanFitInInt32())
5594+
belowX += power.EInteger.ToInt32Checked();
5595+
else
5596+
belowOtherwise = belowOtherwise == Number.Integer.One ? factor : belowOtherwise * factor;
55845597
Entity lowered = Number.Integer.Zero;
55855598
foreach (var term in aboveTerms)
55865599
{
5587-
var power = term.Key.Subtract(EInteger.FromInt32(j));
5588-
if (power.Sign < 0 || term.Value.ContainsNode(x))
5600+
var power = term.Key.Subtract(EInteger.FromInt32(j + belowX));
5601+
if ((belowX == 0 && power.Sign < 0) || term.Value.ContainsNode(x))
55895602
return null;
55905603
var monomial = power.IsZero ? term.Value : term.Value * MathS.Pow(x, Number.Integer.Create(power));
55915604
lowered = lowered == Number.Integer.Zero ? monomial : lowered + monomial;
55925605
}
5593-
rest = restBelow == Number.Integer.One ? lowered : lowered / restBelow;
5606+
rest = belowOtherwise == Number.Integer.One ? lowered : lowered / belowOtherwise;
55945607
}
55955608
var xToTheN = Variable.CreateUnique(expr, "x_n");
55965609
var inXToTheN = rest.Replace(node =>
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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 power of x below the bar beside a root of a binomial in <c>x^n</c> and a rational function
16+
/// of <c>x^n</c>, rationalised by <c>u = x/(a + b x^n)^(1/n)</c>: <c>x^(-2)</c> is <c>x</c>
17+
/// times <c>x^(-3)</c>. Rubi's 1.1.3.4.
18+
/// <a href="https://github.com/asc-community/AngouriMath/issues/718">#718</a>
19+
/// </summary>
20+
[Trait("Area", "Calculus")]
21+
public sealed class APowerOfXBelowTheBarBesideARootOfABinomialIntegralTest
22+
{
23+
[Theory]
24+
[InlineData("(a + b*x^3)^(1/3)/(x^2*(c + d*x^3))", "0.35 0.6 0.85 1.4")]
25+
[InlineData("(a + b*x^3)^(1/3)/(x^5*(c + d*x^3))", "0.35 0.6 0.85 1.4")]
26+
[InlineData("(a + b*x^3)^(4/3)/(x^2*(c + d*x^3))", "0.35 0.6 0.85 1.4")]
27+
[InlineData("1/(x^2*(a + b*x^3)^(2/3)*(c + d*x^3))", "0.35 0.6 0.85 1.4")]
28+
[InlineData("(a + b*x^3)^(1/3)/(x^2*(a*d - b*d*x^3))", "0.35 0.6 1.4 1.8")]
29+
[InlineData("1/(x^2*(1 - x^3)^(2/3)*(1 + x^3))", "0.35 0.6 0.8 0.95")]
30+
public void DifferentiatesBack(string integrand, string points)
31+
{
32+
var integral = integrand.ToEntity().Integrate("x");
33+
Assert.DoesNotContain("integral(", integral.Stringize());
34+
Entity Pinned(Entity e) => e.Substitute("a", 2).Substitute("b", 3).Substitute("c", 5).Substitute("d", 7);
35+
var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x");
36+
var original = Pinned(integrand.ToEntity());
37+
foreach (var at in points.Split(' '))
38+
{
39+
var want = original.Substitute("x", at.ToEntity()).EvalNumerical();
40+
var got = derivative.Substitute("x", at.ToEntity()).EvalNumerical();
41+
Assert.True(Math.Abs((double)(got - want).RealPart) + Math.Abs((double)(got - want).ImaginaryPart)
42+
< 1e-9 * Math.Max(1, Math.Abs((double)want.RealPart)),
43+
$"d/dx of the antiderivative of {integrand} is {got} at x = {at}, where the integrand is {want}");
44+
}
45+
}
46+
}
47+
}

0 commit comments

Comments
 (0)