Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,24 @@ back after. Each answer is in three cases by the sign of `4 a/c - (b/c)^2`
| `"x^5/(a + b*x + c*x^2)^5".ToEntity().Integrate("x")` | `integral(...)` | 4,066 characters |
| `"x^7/(a + b*x + c*x^2)^5".ToEntity().Integrate("x")` | `integral(...)` | 5,602 characters |

### A power of x below the bar beside a root of a binomial is rationalised by dividing by the root

**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
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)`.
`u = x/(a + b x^3)^(1/3)` makes each rational, and was used where the power of x stood above the bar only:
`x^(-2)` is `x` times `x^(-3)`, and the second is a function of `x^3` like the rest
([#718](https://github.com/asc-community/AngouriMath/issues/718)).

| Input | Was (2.5.0) | Now |
|---|---|---|
| `"(a + b*x^3)^(1/3)/(x^2*(c + d*x^3))".ToEntity().Integrate("x")` | `integral(...)` | 857 characters |
| `"(a + b*x^3)^(1/3)/(x^11*(c + d*x^3))".ToEntity().Integrate("x")` | `integral(...)` | 4,974 characters |
| `"(a + b*x^3)^(4/3)/(x^2*(c + d*x^3))".ToEntity().Integrate("x")` | `integral(...)` | 1,562 characters |
| `"(a + b*x^3)^(4/3)/(x^14*(c + d*x^3))".ToEntity().Integrate("x")` | `integral(...)` | 6,092 characters |
| `"1/(x^2*(a + b*x^3)^(2/3)*(c + d*x^3))".ToEntity().Integrate("x")` | `integral(...)` | 1,586 characters |
| `"(a + b*x^3)^(1/3)/(x^2*(a*d - b*d*x^3))".ToEntity().Integrate("x")` | `integral(...)` | 773 characters |
| `"1/(x^2*(1 - x^3)^(2/3)*(1 + x^3))".ToEntity().Integrate("x")` | `integral(...)` | 471 characters |

### `a + i a tan` beside the tangent's differential is lowered over its conjugate

**Answers where there were none.** `sqrt(a + i a tan(x))/(c + d tan(x))^(3/2)` ran past thirty seconds:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5528,7 +5528,10 @@ Entity Carried(int numerator, int denominator, int nextSine, int nextCosine)
/// <c>u^j</c> times the same in <c>u</c>, since <c>x^j (c + d x^n)^(-j/n)</c> is
/// <c>u^j</c>. Rubi's 1.1.3.4: <c>x/((a + b x^3)^(2/3) (c + d x^3))</c> is
/// <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
/// same with <c>x^3</c> beside it; each was declined.
/// same with <c>x^3</c> beside it; each was declined. A power of x below the bar is read
/// the same way, with the multiple of <c>n</c> it leaves going into the rational function:
/// <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>
/// times <c>(a + b x^3)^(1 - 2/3)</c>, Rubi's 1.1.3.4:763.
/// </para>
/// https://github.com/asc-community/AngouriMath/issues/718
/// </remarks>
Expand Down Expand Up @@ -5577,20 +5580,30 @@ Entity Carried(int numerator, int denominator, int nextSine, int nextCosine)
// stand-in for x^n where every power of x is a multiple of n, and declined otherwise.
if (j != 0)
{
// Out of the polynomial above the bar, each of whose powers is then a multiple of n.
// Out of the polynomial above the bar together with the power of x below it, each
// power then a multiple of n, below zero too: `x^(-2)` is `x` times `x^(-3)`.
var (restAbove, restBelow) = Functions.SingleQuotient.Of(rest);
if (!TreeAnalyzer.TryGetPolynomial(restAbove, x, out var aboveTerms) || aboveTerms.Count == 0)
return null;
var belowX = 0;
Entity belowOtherwise = Number.Integer.One;
foreach (var factor in Mulf.LinearChildren(restBelow))
if (factor == x)
belowX++;
else if (factor is Powf(var xAgain, Number.Integer power) && xAgain == x && power.EInteger.Sign > 0 && power.EInteger.CanFitInInt32())
belowX += power.EInteger.ToInt32Checked();
else
belowOtherwise = belowOtherwise == Number.Integer.One ? factor : belowOtherwise * factor;
Entity lowered = Number.Integer.Zero;
foreach (var term in aboveTerms)
{
var power = term.Key.Subtract(EInteger.FromInt32(j));
if (power.Sign < 0 || term.Value.ContainsNode(x))
var power = term.Key.Subtract(EInteger.FromInt32(j + belowX));
if ((belowX == 0 && power.Sign < 0) || term.Value.ContainsNode(x))
return null;
var monomial = power.IsZero ? term.Value : term.Value * MathS.Pow(x, Number.Integer.Create(power));
lowered = lowered == Number.Integer.Zero ? monomial : lowered + monomial;
}
rest = restBelow == Number.Integer.One ? lowered : lowered / restBelow;
rest = belowOtherwise == Number.Integer.One ? lowered : lowered / belowOtherwise;
}
var xToTheN = Variable.CreateUnique(expr, "x_n");
var inXToTheN = rest.Replace(node =>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//
// Copyright (c) 2019-2026 Angouri.
// AngouriMath is licensed under MIT.
// Details: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.
// Website: https://am.angouri.org.
//

using System;
using AngouriMath.Extensions;
using Xunit;

namespace AngouriMath.Tests.Calculus
{
/// <summary>
/// A power of x below the bar beside a root of a binomial in <c>x^n</c> and a rational function
/// 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>
/// times <c>x^(-3)</c>. Rubi's 1.1.3.4.
/// <a href="https://github.com/asc-community/AngouriMath/issues/718">#718</a>
/// </summary>
[Trait("Area", "Calculus")]
public sealed class APowerOfXBelowTheBarBesideARootOfABinomialIntegralTest
{
[Theory]
[InlineData("(a + b*x^3)^(1/3)/(x^2*(c + d*x^3))", "0.35 0.6 0.85 1.4")]
[InlineData("(a + b*x^3)^(1/3)/(x^5*(c + d*x^3))", "0.35 0.6 0.85 1.4")]
[InlineData("(a + b*x^3)^(4/3)/(x^2*(c + d*x^3))", "0.35 0.6 0.85 1.4")]
[InlineData("1/(x^2*(a + b*x^3)^(2/3)*(c + d*x^3))", "0.35 0.6 0.85 1.4")]
[InlineData("(a + b*x^3)^(1/3)/(x^2*(a*d - b*d*x^3))", "0.35 0.6 1.4 1.8")]
[InlineData("1/(x^2*(1 - x^3)^(2/3)*(1 + x^3))", "0.35 0.6 0.8 0.95")]
public void DifferentiatesBack(string integrand, string points)
{
var integral = integrand.ToEntity().Integrate("x");
Assert.DoesNotContain("integral(", integral.Stringize());
Entity Pinned(Entity e) => e.Substitute("a", 2).Substitute("b", 3).Substitute("c", 5).Substitute("d", 7);
var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x");
var original = Pinned(integrand.ToEntity());
foreach (var at in points.Split(' '))
{
var want = original.Substitute("x", at.ToEntity()).EvalNumerical();
var got = derivative.Substitute("x", at.ToEntity()).EvalNumerical();
Assert.True(Math.Abs((double)(got - want).RealPart) + Math.Abs((double)(got - want).ImaginaryPart)
< 1e-9 * Math.Max(1, Math.Abs((double)want.RealPart)),
$"d/dx of the antiderivative of {integrand} is {got} at x = {at}, where the integrand is {want}");
}
}
}
}
Loading