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 @@ -2353,6 +2353,19 @@ a sample of its families 1 to 7 are answered alone as they were.
| `"x^2*Ei(a+b*x)^2".Integrate("x")` | `a ^ 2 * Ei * x ^ 3 / 3 + a * b * 2 * Ei * x ^ 4 / 4 + b ^ 2 * Ei * x ^ 5 / 5 + C`, with `Ei` a variable | an antiderivative in `Ei(a + b x)` and `Ei(2 (a + b x))` |
| `"erf(a+b*x)^2".Integrate("x")` | `UnrecognizedFunctionParseException`: there is no function `erf` | an antiderivative in `erf` |

### A logarithm of `x` is matched to a logarithm of a multiple of `x` below the bar

By parts on `li(b x)/x` takes the antiderivative of `1/x`, and with `ln(x)` the remainder was
`b ln(x)/ln(b x)`, which nothing read. `ln(b x)` is as much an antiderivative of `1/x`, and taken so,
the logarithm the derivative of `li(b x)` divides by cancels: `li(b x)/x` is `li(b x) ln(b x) - b x`
([#1501](https://github.com/asc-community/AngouriMath/issues/1501)). `li` had no reading in 2.5.0,
which its own entry records, and no integrand without it changes: Rubi's independent suites, its
family 3 at twenty a file and a sample of the others are answered alone as they were.

| Input | Was (2.5.0) | Now |
|---|---|---|
| `"li(b*x)/x".Integrate("x")` | `li * b * x + C`, with `li` a variable | `li(b * x) * ln(b * x) - b * x + C` |

### An exponential or a hyperbolic function over several linears is split into partial fractions over them

`e^x/(x (x + 1))` was left unevaluated, where `e^x/x` and `e^x/(x + 1)` were each answered with
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1679,6 +1679,18 @@ private static bool IsASpecialFunctionOfALinear(Entity factor, Variable x)
// divisor, where the division leaves a constant.
static Entity WithTheConstantMatchedTo(Entity antiderivative, Entity derivativeOfV, Variable x)
{
// A logarithm of x, against a logarithm of a multiple of x below the bar: ln(c x) is
// as much an antiderivative of 1/x as ln(x) is, and taken so, the logarithm the
// derivative divides by cancels. li(b x)/x is li(b x) ln(b x) - b x, where with ln(x)
// the remainder was ln(x)/ln(b x), which nothing read.
// https://github.com/asc-community/AngouriMath/issues/1501
if (TheLogarithmOfTheVariable(antiderivative, x) is (var logarithmCoefficient, true)
&& Sumf.LinearChildren(Functions.PartialFractions.Bare(derivativeOfV))
.SelectMany(term => Mulf.LinearChildren(Functions.SingleQuotient.Of(term).Denominator))
.FirstOrDefault(factor => factor is Logf(var logBase, var argument) && logBase == MathS.e
&& TreeAnalyzer.TryGetPolyLinear(argument, x, out var multiple, out var offset)
&& TreeAnalyzer.IsZero(offset) && !TreeAnalyzer.IsZero(multiple)) is { } logarithmBelow)
return logarithmCoefficient * logarithmBelow;
if (!TreeAnalyzer.TryGetPolynomial(antiderivative, x, out _))
return antiderivative;
var divisors = Sumf.LinearChildren(Functions.PartialFractions.Bare(derivativeOfV))
Expand Down Expand Up @@ -20367,6 +20379,25 @@ private static bool TheRemainderIsAskedTermByTerm(Entity v, Entity u, Variable x
|| u == special;
}

/// <summary>
/// <paramref name="expr"/> as a constant times <c>ln(x)</c>, the coefficient and
/// <see langword="true"/>, or <see langword="false"/> where it is not one.
/// </summary>
private static (Entity Coefficient, bool IsOne) TheLogarithmOfTheVariable(Entity expr, Variable x)
{
static bool IsTheLogarithm(Entity factor, Variable x) => factor is Logf(var logBase, var argument) && logBase == MathS.e && argument == x;
if (IsTheLogarithm(expr, x))
return (Number.Integer.One, true);
if (expr is Mulf(var left, var right))
{
if (IsTheLogarithm(right, x) && !left.ContainsNode(x))
return (left, true);
if (IsTheLogarithm(left, x) && !right.ContainsNode(x))
return (right, true);
}
return (Number.Integer.Zero, false);
}

/// <summary>
/// The factors of <paramref name="expr"/> that are polynomials in <paramref name="x"/> of
/// positive degree, against the rest: <c>x sin(b x)</c> is <c>x</c> and <c>sin(b x)</c>.
Expand Down
16 changes: 15 additions & 1 deletion Sources/Tests/UnitTests/Calculus/SpecialFunctionsByPartsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,17 @@ public sealed class SpecialFunctionsByPartsTest
/// rule is asked the symbolic question.
/// </summary>
private static void DifferentiatesBack(string integrand, params (string Name, string Value)[] pins)
=> DifferentiatesBackAt(Points, integrand, pins);

/// <summary><see cref="DifferentiatesBack"/> at <paramref name="points"/>.</summary>
private static void DifferentiatesBackAt(double[] points, string integrand, params (string Name, string Value)[] pins)
{
var integral = integrand.ToEntity().Integrate("x");
Assert.DoesNotContain("integral(", integral.Stringize());
Entity Pinned(Entity e) => pins.Aggregate(e, (current, pin) => current.Substitute(pin.Name, pin.Value.ToEntity()));
var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x");
var original = Pinned(integrand.ToEntity());
foreach (var at in Points)
foreach (var at in points)
{
var got = derivative.Substitute("x", at).EvalNumerical();
var want = original.Substitute("x", at).EvalNumerical();
Expand Down Expand Up @@ -73,6 +77,16 @@ public void ASpecialFunctionAloneIsByPartsAgainstOne(string integrand)
public void TheLogarithmicIntegralIsByParts(string integrand)
=> DifferentiatesBack(integrand, ("a", "3"), ("b", "13/10"));

/// <summary>
/// Over <c>x</c>, the antiderivative of <c>1/x</c> is taken as <c>ln(b x)</c>, the logarithm the
/// derivative of <c>li(b x)</c> divides by, and the remainder is <c>b</c>:
/// <c>li(b x) ln(b x) - b x</c>. At positive <c>x</c>, where <c>li(b x)</c> is real, and off
/// <c>x = 1/b</c>, where <c>ln(b x)</c> is 0.
/// </summary>
[Fact]
public void TheLogarithmicIntegralOverXIsOneRoundOfParts()
=> DifferentiatesBackAt(new[] { 0.35, 1.45, 2.3 }, "li(b*x)/x", ("b", "13/10"));

/// <summary>
/// Against a power of <c>x</c>, the special function is the factor differentiated: what is
/// left is the power times <c>e^(-u^2)</c>, <c>e^u/u</c>, <c>sin(u)/u</c> and the like.
Expand Down
Loading