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
13 changes: 13 additions & 0 deletions BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,19 @@ square and the cube keep the Hermite reduction's answers. Rubi's 1.1.3.8 `P(x) (
| `"(c + d*x)/(a + b*x^3)^4".ToEntity().Integrate("x")` | `integral(...)` | the same at the roots of `a + b x^3` |
| `"x^2/(a + b*x^5)^5".ToEntity().Integrate("x")` | `integral(...)` | four algebraic terms, and the integral of `x^2/(a + b x^5)` |

### A difference is offered to the substitution search as a sum is

**Answers where there were none.** `sin(1 + 2/(1 + x))` was answered under `u = 1 + x`, and
`sin(1 + 2/(1 - x))` was declined: the substitution search offered every sum in the integrand as a
candidate and no difference, so `u = 1 - x` was never tried. A difference in the integrand as asked
is offered now as a sum is ([#718](https://github.com/asc-community/AngouriMath/issues/718)).

| Input | Was (2.5.0) | Now |
|---|---|---|
| `"sin(1 + 2/(1 - x))".ToEntity().Integrate("x")` | `integral(...)` | in the sine and cosine integrals of `2/(1 - x)` |
| `"cos(1 + 2/(x - 1))".ToEntity().Integrate("x")` | `integral(...)` | in the sine and cosine integrals of `2/(x - 1)` |
| `"sin(p + k/(c - d*x))".ToEntity().Integrate("x")` | `integral(...)` | in the sine and cosine integrals of `k/(c - d x)` |

### A polynomial over a power of a trinomial past the square is integrated

`P(x)/(a + b x^n + c x^(2n))^k`, a polynomial over a power of a trinomial in `x^n` with symbols in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26266,7 +26266,7 @@ private static bool IsAFunctionOfTheTangentAlone(Entity expr, Entity.Variable u)
// and not a subexpression anyone wrote: `1 + 2x^2` and `1 + 2x^2 + 4x^3` are
// the left-nested partial sums of Hearn's radicand `1 + 2x^2 + 4x^3 + x^4`,
// and each was half a second of rewriting and simplifying to be refused.
if (u is Sumf && IsOnlyAPartialSum(expr, u))
if (u is Sumf or Minusf && IsOnlyAPartialSum(expr, u))
continue;

// A candidate that does not vary with x is no substitution at all, and its
Expand Down Expand Up @@ -27147,8 +27147,14 @@ bool APowerCanBeExact(int k)
case var special when IsASpecialFunction(special) && TheDifferentialCanBeThere(special, expr, x):
candidates.Add(node);
break;
case Sumf(var aug, var add) when !rational && !large && node.Complexity <= LargestSumOffered:
if (aug.ContainsNode(x) || add.ContainsNode(x)) candidates.Add(node); // Linear expressions ax + b
// A difference as a sum: `1 - x` below the bar of `sin(1 + 2/(1 - x))` is the
// substitution that `1 + x` is for `sin(1 + 2/(1 + x))`, and was never offered.
// In the question asked only: below it every substitution writes differences,
// `x = (u^2 - c)/d`, and offering them was two fifths more search on Rubi's
// `(c + d x)^(5/2)/(x (a + b x)^2)`, past the harness's patience.
case Sumf or Minusf when !rational && !large && node.Complexity <= LargestSumOffered
&& (node is Sumf || Integration.AnsweringTheQuestionAsked):
if (node.DirectChildren.Any(child => child.ContainsNode(x))) candidates.Add(node); // Linear expressions ax + b
break;
}
// Sort by complexity - try simpler substitutions first
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//
// 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 difference offered to the substitution search as a sum is: <c>sin(1 + 2/(1 - x))</c> is
/// <c>-sin(1 + 2/u)</c> under <c>u = 1 - x</c>, as <c>sin(1 + 2/(1 + x))</c> is
/// <c>sin(1 + 2/u)</c> under <c>u = 1 + x</c>, and only the second was answered.
/// <a href="https://github.com/asc-community/AngouriMath/issues/718">#718</a>
/// </summary>
/// <remarks>
/// Checked by differentiating back with <c>p = 0.3</c>, <c>k = 0.9</c>, <c>c = 1.1</c>,
/// <c>d = 0.7</c>, on both sides of the pole of every row.
/// </remarks>
[Trait("Area", "Calculus")]
public sealed class DifferenceAsASubstitutionIntegralTest
{
[Theory]
[InlineData("sin(1 + 2/(1 - x))")]
[InlineData("cos(1 + 2/(1 - x))")]
[InlineData("sin(1 + 2/(x - 1))")]
[InlineData("sin(1 + 2/(3 - 2*x))")]
[InlineData("sin(p + k/(c - d*x))")]
public void IsSubstitutedForAsASumIs(string integrand)
{
var integral = integrand.ToEntity().Integrate("x");
Assert.DoesNotContain("integral(", integral.Stringize());
Entity Pinned(Entity e) => e.Substitute("p", 0.3).Substitute("k", 0.9).Substitute("c", 1.1).Substitute("d", 0.7);
var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x");
var original = Pinned(integrand.ToEntity());
foreach (var at in new[] { -1.0, 0.3, 0.8, 2.2, 3.0 })
{
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) + Math.Abs((double)want.ImaginaryPart)),
$"d/dx of the antiderivative of {integrand} is {got} at x = {at}, where the integrand is {want}");
}
}
}
}
Loading