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
12 changes: 12 additions & 0 deletions BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,18 @@ partial fractions divide. It is taken out in front of the integral first
| `"(b*d + 2*c*d*x)^9/(a + b*x + c*x^2)^3".ToEntity().Integrate("x")` | past a minute | 76,249 characters, the length the content-free one already had |
| `"(b*d + 2*c*d*x)^8/(a + b*x + c*x^2)^3".ToEntity().Integrate("x")` | past a minute | 65,236 characters |

### A power of x past the twelfth beside a block is split off

**Answers where there were none.** `(c + d x^3 + g x^6 + f x^9)/(x^14 (a + b x^3))` was declined, and so were
`x^13` to `x^17` beside `(a + b x^3)`, its square and its cube, Rubi's 1.1.3.8. The split that writes `N/(x^k B)` as
`P/x^k + R/B`, with `P` the first `k` terms of the series of `N/B` at 0, took `k` up to 12. It takes `k` up to 24
now, where the series costs one term per power
([#718](https://github.com/asc-community/AngouriMath/issues/718)).

| Input | Was (2.5.0) | Now |
|---|---|---|
| `"(c + d*x^3 + g*x^6 + f*x^9)/(x^14*(a + b*x^3))".ToEntity().Integrate("x")` | `integral(...)` | the antiderivative, in powers of x and the logarithms and arctangent of `a + b x^3`'s factors |

### A symbolic quadratic with a square discriminant is split into its linears before the division

**Answers where there were none.** `(d + e x)^8/(a d e + (c d^2 + a e^2) x + c d e x^2)^2` ran past a minute, with
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1245,7 +1245,7 @@ private static (Entity InY, Entity.Variable Y, Entity Shift)? InTheVariableThatD
pastTheSecondDegree |= TreeAnalyzer.TryGetPolynomial(written, x, out var terms) && terms.Keys.Any(power => power.CompareTo(EInteger.FromInt32(2)) > 0);
}
}
if (k == 0 || k > MaximumPowerOfXBesideABlock || !pastTheSecondDegree || !block.ContainsNode(x) || !block.Vars.Any(symbol => symbol != x))
if (k == 0 || k > MaximumPowerOfXOverABlock || !pastTheSecondDegree || !block.ContainsNode(x) || !block.Vars.Any(symbol => symbol != x))
return null;
if (!TreeAnalyzer.TryGetPolynomial(block, x, out var below) || !TreeAnalyzer.TryGetPolynomial(numerator, x, out var above))
return null;
Expand Down Expand Up @@ -1581,11 +1581,19 @@ Entity InU(Dictionary<EInteger, Entity> polynomial)
}

/// <summary>
/// The largest power of x, and the largest degree of the block beside it, that
/// <see cref="IntegrateOverAPowerOfXBesideABlock"/> takes: Rubi's suite goes to twelve.
/// The largest degree of a block beside a power of x that
/// <see cref="IntegrateOverAPowerOfXBesideABlock"/> takes; also the largest power of a
/// linear beside a block, and of x in blocks of <see cref="IntegrateOverBlocksInAPowerOfX"/>.
/// </summary>
private const int MaximumPowerOfXBesideABlock = 12;

/// <summary>
/// The largest power of x that <see cref="IntegrateOverAPowerOfXBesideABlock"/> takes. The
/// series it writes has one term per power of x, so the cost grows linearly in it. Rubi's
/// suite asks for up to <c>x^17</c>, beside <c>(a + b x^3)^3</c>.
/// </summary>
private const int MaximumPowerOfXOverABlock = 24;

/// <summary>
/// A polynomial over a power of a binomial, <c>P(x)/(a + b x^n)^k</c> with <c>n &gt;= 3</c>
/// and <c>k &gt;= 2</c>, a power at a time down to <c>P'(x)/(a + b x^n)</c>, which
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// 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 past the twelfth beside a block with symbols in it is split off as the first
/// terms of the block's series at 0: Rubi's 1.1.3.8 asks for up to <c>x^17</c> beside
/// <c>(a + b x^3)^3</c>.
/// <a href="https://github.com/asc-community/AngouriMath/issues/718">#718</a>
/// </summary>
[Trait("Area", "Calculus")]
public sealed class AHighPowerOfXBesideABlockIntegralTest
{
[Theory]
[InlineData("(c + d*x^3 + g*x^6 + f*x^9)/(x^14*(a + b*x^3))")]
[InlineData("(c + d*x^3 + g*x^6 + f*x^9)/(x^17*(a + b*x^3))")]
[InlineData("(c + d*x^3 + g*x^6 + f*x^9)/(x^14*(a + b*x^3)^2)")]
public void DifferentiatesBack(string integrand)
{
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", -1).Substitute("g", 7).Substitute("f", 1);
var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x");
var original = Pinned(integrand.ToEntity());
foreach (var at in new[] { -1.7, -0.6, 0.45, 1.3 })
{
var want = original.Substitute("x", at).EvalNumerical();
var got = derivative.Substitute("x", at).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