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 @@ -470,6 +470,24 @@ by the linear's coefficients, `(b d + 2c d x)^9`, which ran past a minute
| `"(b + 2*c*x)^9/(a + b*x + c*x^2)^3".ToEntity().Integrate("x")` | past a minute; 76,153 characters on the unreleased master | 607 characters |
| `"(b*d + 2*c*d*x)^9/(a + b*x + c*x^2)^3".ToEntity().Integrate("x")` | past a minute | 611 characters |

### A quadratic's half-odd power beside a power of another quadratic is integrated

**Answers where there were none.** `sqrt(3 - x + 2 x^2)/(2 + 3 x + 5 x^2)^2` was declined, and so were
`1/((3 - x + 2 x^2)^(5/2) (2 + 3 x + 5 x^2))` and most of Rubi's 1.2.1.5 past the first powers. Above the bar the root
was not read: `B^(n/2)` is `B^((n + 1)/2)` over `sqrt(B)`, a polynomial over the root, which the reduction over a power
of the other quadratic answers. Below it, the split of the rational part over the two quadratics declined a repeated
quadratic with numbers in it, although beside the root each piece is a shape the rules read
([#718](https://github.com/asc-community/AngouriMath/issues/718)).

| Input | Was (2.5.0) | Now |
|---|---|---|
| `"sqrt(3 - x + 2*x^2)/(2 + 3*x + 5*x^2)^2".ToEntity().Integrate("x")` | `integral(...)` | 1,344 characters |
| `"(3 - x + 2*x^2)^(3/2)/(2 + 3*x + 5*x^2)^3".ToEntity().Integrate("x")` | `integral(...)` | 1,451 characters |
| `"1/((3 - x + 2*x^2)^(5/2)*(2 + 3*x + 5*x^2))".ToEntity().Integrate("x")` | `integral(...)` | 1,380 characters |
| `"1/((3 - x + 2*x^2)^(5/2)*(2 + 3*x + 5*x^2)^3)".ToEntity().Integrate("x")` | `integral(...)` | 1,629 characters |
| `"(2 + 5*x + x^2)*sqrt(3 + 2*x + 5*x^2)/(1 + 4*x - 7*x^2)^3".ToEntity().Integrate("x")` | `integral(...)` | 5,242 characters |
| `"(a + b*x + c*x^2)^(1/2)/(d + e*x + f*x^2)^2".ToEntity().Integrate("x")` | `integral(...)` | 50,758 characters, six symbols |

### A square of a symbolic quadratic beside two linears is answered within the budget

**Answers where there were none in time.** `1/((d + k x)(f + g x)(a + b x + c x^2)^2)` was declined by
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,12 @@ private static Entity AsFraction(RationalPolynomial numerator, RationalPolynomia
/// https://github.com/asc-community/AngouriMath/issues/718
/// </remarks>
internal static bool TrySplitOverWrittenFactors(
Entity numerator, Entity denominator, Variable x, [NotNullWhen(true)] out Entity? decomposition)
Entity numerator, Entity denominator, Variable x, [NotNullWhen(true)] out Entity? decomposition,
// Whether the caller reads a polynomial over a power of a quadratic with numbers in
// it, as the rules beside the square root of a quadratic do: over the radicand's power
// it is a polynomial times a half-odd power of the radicand, and over another
// quadratic's a polynomial over a power of a quadratic beside the root of another.
bool aRepeatedQuadraticIsRead = false)
{
decomposition = null;

Expand Down Expand Up @@ -464,7 +469,7 @@ internal static bool TrySplitOverWrittenFactors(
// A repeated quadratic has a rule to land on only with a symbol somewhere,
// the split by residues below; over the rationals the system would hand it a
// cubic over the square, which no rule reads.
if (multiplicity > 1 && degree.ToInt32Unchecked() != 1 && !(numerator + denominator).Vars.Any(v => v != x))
if (multiplicity > 1 && degree.ToInt32Unchecked() != 1 && !aRepeatedQuadraticIsRead && !(numerator + denominator).Vars.Any(v => v != x))
return false;
foreach (var pair in read)
if (pair.Key.Sign < 0 || pair.Value.ContainsNode(x))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18271,6 +18271,24 @@ Dictionary<EInteger, Entity> PowerOfQ(int j)
else
return null;
}
// The root above the bar: `B^(n/2)` for an odd `n` is `B^((n + 1)/2)/sqrt(B)`, a
// polynomial over the root. `sqrt(3 - x + 2 x^2)/(2 + 3 x + 5 x^2)^2` was declined,
// the reduction reading only a root below (Rubi's 1.2.1.5).
if (radicand is null && quadratic is not null)
{
Entity rest = Number.Integer.One;
foreach (var factor in Mulf.LinearChildren(numerator))
if (radicand is null && factor is Powf(var @base, Number.Rational { ERational: var exponent })
&& exponent.Denominator.Equals(EInteger.FromInt32(2)) && exponent.Numerator.Sign > 0
&& exponent.Numerator.CanFitInInt32() && @base.ContainsNode(x))
{
radicand = @base;
rest = rest * MathS.Pow(@base, (exponent.Numerator.ToInt32Unchecked() + 1) / 2);
}
else
rest = rest * factor;
numerator = rest;
}
if (radicand is null || quadratic is null || quadratic == radicand
|| !TreeAnalyzer.TryGetPolyQuadratic(quadratic, x, out var a2, out var a1, out var a0)
|| !TreeAnalyzer.TryGetPolyQuadratic(radicand, x, out var b2, out var b1, out var b0)
Expand Down Expand Up @@ -18613,7 +18631,8 @@ static Entity WithoutConditions(Entity coefficient)
{
if (factors.Count == 1)
pieces.Add(properNumerator / factors[0]);
else if (Functions.PartialFractions.TrySplitOverWrittenFactors(properNumerator, linears, x, out var decomposition) && decomposition is not null)
else if (Functions.PartialFractions.TrySplitOverWrittenFactors(properNumerator, linears, x, out var decomposition, aRepeatedQuadraticIsRead: true)
&& decomposition is not null)
{
// The split comes back as a sum over a constant; the constant goes to each term.
var (terms, over) = decomposition is Divf(var splitTop, var splitBottom) && !splitBottom.ContainsNode(x)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,22 @@ public void APolynomialPartBeside(string integrand)
public void OverAPowerOfTheQuadratic(string integrand)
=> DifferentiatesBackPinned(integrand, new[] { 0.3, 0.7, 0.9, -0.5 }, Pins);

/// <summary>
/// The root above the bar, <c>B^(n/2)</c> as <c>B^((n + 1)/2)</c> over the root; and a
/// power of the radicand below it beside a power of the other quadratic, where the split
/// has a numeric repeated quadratic in it, a polynomial over its power beside the root
/// that the reductions read. Rubi's 1.2.1.5, declined before.
/// </summary>
[Theory]
[InlineData("sqrt(3 - x + 2*x^2)/(2 + 3*x + 5*x^2)^2")]
[InlineData("(3 - x + 2*x^2)^(3/2)/(2 + 3*x + 5*x^2)^3")]
[InlineData("(a + b*x + c*x^2)^(1/2)/(d + k*x + f*x^2)^2")]
[InlineData("1/((3 - x + 2*x^2)^(3/2)*(2 + 3*x + 5*x^2)^2)")]
[InlineData("1/((3 - x + 2*x^2)^(5/2)*(2 + 3*x + 5*x^2))")]
[InlineData("1/((3 - x + 2*x^2)^(5/2)*(1 + x^2))")]
public void TheRootAboveOrItsRadicandRepeated(string integrand)
=> DifferentiatesBackPinned(integrand, new[] { 0.3, 0.7, 0.9, -0.5 }, Pins);

/// <summary>
/// Beside a half-odd power of <c>a + a sec(x)</c>, the half-angle tangent leaves a power
/// of <c>(c + d) + (d - c) t^2</c> below the bar, which ran out Rubi's budget in 4.5.2.1.
Expand Down
Loading