Skip to content

Commit 94e9a6a

Browse files
A power of x past the twelfth beside a block is split off (#1840)
Part of #718. Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent 3c86dda commit 94e9a6a

3 files changed

Lines changed: 68 additions & 3 deletions

File tree

‎BREAKING-CHANGES.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,18 @@ partial fractions divide. It is taken out in front of the integral first
205205
| `"(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 |
206206
| `"(b*d + 2*c*d*x)^8/(a + b*x + c*x^2)^3".ToEntity().Integrate("x")` | past a minute | 65,236 characters |
207207

208+
### A power of x past the twelfth beside a block is split off
209+
210+
**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
211+
`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
212+
`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
213+
now, where the series costs one term per power
214+
([#718](https://github.com/asc-community/AngouriMath/issues/718)).
215+
216+
| Input | Was (2.5.0) | Now |
217+
|---|---|---|
218+
| `"(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 |
219+
208220
### A symbolic quadratic with a square discriminant is split into its linears before the division
209221

210222
**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

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,7 +1245,7 @@ private static (Entity InY, Entity.Variable Y, Entity Shift)? InTheVariableThatD
12451245
pastTheSecondDegree |= TreeAnalyzer.TryGetPolynomial(written, x, out var terms) && terms.Keys.Any(power => power.CompareTo(EInteger.FromInt32(2)) > 0);
12461246
}
12471247
}
1248-
if (k == 0 || k > MaximumPowerOfXBesideABlock || !pastTheSecondDegree || !block.ContainsNode(x) || !block.Vars.Any(symbol => symbol != x))
1248+
if (k == 0 || k > MaximumPowerOfXOverABlock || !pastTheSecondDegree || !block.ContainsNode(x) || !block.Vars.Any(symbol => symbol != x))
12491249
return null;
12501250
if (!TreeAnalyzer.TryGetPolynomial(block, x, out var below) || !TreeAnalyzer.TryGetPolynomial(numerator, x, out var above))
12511251
return null;
@@ -1581,11 +1581,19 @@ Entity InU(Dictionary<EInteger, Entity> polynomial)
15811581
}
15821582

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

1590+
/// <summary>
1591+
/// The largest power of x that <see cref="IntegrateOverAPowerOfXBesideABlock"/> takes. The
1592+
/// series it writes has one term per power of x, so the cost grows linearly in it. Rubi's
1593+
/// suite asks for up to <c>x^17</c>, beside <c>(a + b x^3)^3</c>.
1594+
/// </summary>
1595+
private const int MaximumPowerOfXOverABlock = 24;
1596+
15891597
/// <summary>
15901598
/// A polynomial over a power of a binomial, <c>P(x)/(a + b x^n)^k</c> with <c>n &gt;= 3</c>
15911599
/// and <c>k &gt;= 2</c>, a power at a time down to <c>P'(x)/(a + b x^n)</c>, which
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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 past the twelfth beside a block with symbols in it is split off as the first
16+
/// terms of the block's series at 0: Rubi's 1.1.3.8 asks for up to <c>x^17</c> beside
17+
/// <c>(a + b x^3)^3</c>.
18+
/// <a href="https://github.com/asc-community/AngouriMath/issues/718">#718</a>
19+
/// </summary>
20+
[Trait("Area", "Calculus")]
21+
public sealed class AHighPowerOfXBesideABlockIntegralTest
22+
{
23+
[Theory]
24+
[InlineData("(c + d*x^3 + g*x^6 + f*x^9)/(x^14*(a + b*x^3))")]
25+
[InlineData("(c + d*x^3 + g*x^6 + f*x^9)/(x^17*(a + b*x^3))")]
26+
[InlineData("(c + d*x^3 + g*x^6 + f*x^9)/(x^14*(a + b*x^3)^2)")]
27+
public void DifferentiatesBack(string integrand)
28+
{
29+
var integral = integrand.ToEntity().Integrate("x");
30+
Assert.DoesNotContain("integral(", integral.Stringize());
31+
Entity Pinned(Entity e) => e.Substitute("a", 2).Substitute("b", 3).Substitute("c", 5)
32+
.Substitute("d", -1).Substitute("g", 7).Substitute("f", 1);
33+
var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x");
34+
var original = Pinned(integrand.ToEntity());
35+
foreach (var at in new[] { -1.7, -0.6, 0.45, 1.3 })
36+
{
37+
var want = original.Substitute("x", at).EvalNumerical();
38+
var got = derivative.Substitute("x", at).EvalNumerical();
39+
Assert.True(Math.Abs((double)(got - want).RealPart) + Math.Abs((double)(got - want).ImaginaryPart)
40+
< 1e-9 * Math.Max(1, Math.Abs((double)want.RealPart)),
41+
$"d/dx of the antiderivative of {integrand} is {got} at x = {at}, where the integrand is {want}");
42+
}
43+
}
44+
}
45+
}

0 commit comments

Comments
 (0)