Skip to content

Commit b7977b2

Browse files
Keep an antiderivative as found where its inner simplification would multiply it (#2056)
Integrate inner-simplifies the antiderivative before returning it, which drops a branch whose guard is decidably false (#772). It also combines a sum of piecewises case by case, and where their conditions differ as written the arms multiply: Rubi's 1.1.2.2 x^19/(a + b x^2)^10 was answered in 11,811 characters and returned in 5,051,391, ten piecewises of four arms each, which the corpus spent seventeen seconds of its budget differentiating back. Where the simplification makes an answer more than four times larger, by node count, the answer is returned as it was found. Part of #233. Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent 68ae16c commit b7977b2

3 files changed

Lines changed: 75 additions & 1 deletion

File tree

‎BREAKING-CHANGES.md‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,20 @@ It is written out again in the precision asked for now
493493
| `Rational.Create(128, 12167)`'s `EDecimal`, read at the default precision and then under 300 digits | 100 digits | 300 digits |
494494
| `sqrt(46) * 128/12167` evaluated under 300 digits, with that rational | relative error `4.7e-101` | correct to 300 digits |
495495

496+
### An antiderivative is not inner-simplified where that would multiply it
497+
498+
**Shorter answers, where 2.5.0 gave none.** `Integrate` inner-simplifies the antiderivative before returning it, which drops a branch whose
499+
guard is decidably false. A sum of piecewises whose conditions differ as written is combined case by case there. Rubi's
500+
1.1.2.2 `x^19/(a + b x^2)^10` was answered in 11,811 characters, and the combination came to 5,051,391: ten piecewises of
501+
four arms each. The corpus spent seventeen seconds differentiating that back. Where the simplification makes an answer
502+
more than four times larger, the answer is returned as it was found
503+
([#718](https://github.com/asc-community/AngouriMath/issues/718)).
504+
505+
| Input | Was (2.5.0) | Now |
506+
|---|---|---|
507+
| `"x^19/(a+b*x^2)^10".ToEntity().Integrate("x")` | `integral(...)` | 11,815 characters, where before this change master gave 5,051,391 |
508+
| `"x^7/(a+b*x^2)^4".ToEntity().Integrate("x")` | `integral(...)` | 3,269 characters, where before this change master gave 20,387 |
509+
496510
### A polynomial over a power of a linear beside `a + b ln(c x^n)` is integrated by parts against its antiderivative vanishing at zero
497511

498512
**Answers where there were none.** Rubi's 3.1.4 `x^5 (a + b ln(c x^n))/(d + e x)^7` was declined, and on unreleased

‎Sources/AngouriMath/Core/Transformations/Transformation.Catalogue.cs‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1053,8 +1053,20 @@ private sealed class IntegrationTransformation : Transformation
10531053
protected override Entity? ApplyCore(Entity input)
10541054
=> MathS.Settings.DowncastingEnabled.Value ? Integrate(input) : IntegrateExactly(input);
10551055

1056+
/// <remarks>
1057+
/// Inner-simplified, which drops a branch whose guard is decidably false; but not where that
1058+
/// multiplies the answer: a sum of piecewises whose conditions differ as written is combined case
1059+
/// by case, and the 11,811 characters `x^19/(a + b x^2)^10` is answered in came to 5,051,391,
1060+
/// ten piecewises of four arms each, which the corpus spent seventeen seconds differentiating back.
1061+
/// </remarks>
10561062
private Entity? Integrate(Entity input)
1057-
=> Functions.Algebra.Integration.ComputeIndefiniteIntegral(input.InnerSimplified, variable)?.InnerSimplified;
1063+
=> Functions.Algebra.Integration.ComputeIndefiniteIntegral(input.InnerSimplified, variable) is { } antiderivative
1064+
&& antiderivative.InnerSimplified is var simplified
1065+
? simplified.Complexity > LargestGrowthBySimplifying * antiderivative.Complexity ? antiderivative : simplified
1066+
: null;
1067+
1068+
/// <summary>How many times larger the inner simplification of an answer may make it.</summary>
1069+
private const int LargestGrowthBySimplifying = 4;
10581070

10591071
/// <summary>See <see cref="ReadExactly"/>.</summary>
10601072
private Entity? IntegrateExactly(Entity input)
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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+
/// An antiderivative is inner-simplified before it is returned, but not where that multiplies it:
16+
/// Rubi's 1.1.2.2 <c>x^19/(a + b x^2)^10</c> was answered in 11,811 characters, a sum of ten piecewises
17+
/// of four arms each whose conditions differ as written, and combined case by case it came to
18+
/// 5,051,391, which the corpus spent seventeen seconds differentiating back.
19+
/// <a href="https://github.com/asc-community/AngouriMath/issues/718">#718</a>
20+
/// </summary>
21+
[Trait("Area", "Calculus")]
22+
public sealed class AnAntiderivativeItsSimplificationWouldMultiplyIntegralTest
23+
{
24+
[Theory]
25+
// Rubi 1.1.2.2:208.
26+
[InlineData("x^19/(a + b*x^2)^10", 50_000)]
27+
[InlineData("x^7/(a + b*x^2)^4", 10_000)]
28+
public void IsReturnedAtTheSizeItWasFound(string integrand, int mostCharacters)
29+
{
30+
var integral = integrand.ToEntity().Integrate("x");
31+
var text = integral.Stringize();
32+
Assert.DoesNotContain("integral(", text);
33+
Assert.True(text.Length < mostCharacters, $"{integrand} came back in {text.Length} characters");
34+
Entity Pinned(Entity e) => e.Substitute("a", 1.3).Substitute("b", 0.7);
35+
var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x");
36+
var original = Pinned(integrand.ToEntity());
37+
foreach (var at in new[] { -2.2, -0.9, 0.3, 1.4, 2.1 })
38+
{
39+
var want = original.Substitute("x", at).EvalNumerical();
40+
var got = derivative.Substitute("x", at).EvalNumerical();
41+
Assert.False(got.IsNaN, $"d/dx of the antiderivative of {integrand} has no value at x = {at}, where the integrand is {want}");
42+
Assert.True(Math.Abs((double)(got - want).RealPart) + Math.Abs((double)(got - want).ImaginaryPart)
43+
< 1e-9 * Math.Max(1, Math.Abs((double)want.RealPart) + Math.Abs((double)want.ImaginaryPart)),
44+
$"d/dx of the antiderivative of {integrand} is {got} at x = {at}, where the integrand is {want}");
45+
}
46+
}
47+
}
48+
}

0 commit comments

Comments
 (0)