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
15 changes: 15 additions & 0 deletions BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,21 @@ integrals with `0` ([#1769](https://github.com/asc-community/AngouriMath/issues/
| `"e^(-160)".ToEntity().InnerSimplified` | `0` | `e ^ (-160)` |
| `"x^n*((1 - d^2)/x - x)^3*(1 + x^2 - d*x)/(x - d)/pi^2".ToEntity().Simplify()` | `0 provided not x - d = 0 and ...` | `x ^ n * ((1 - d ^ 2) / x - x) ^ 3 * (1 - d * x + x ^ 2) / (pi ^ 2 * (x - d))` |

### `e^(i arctan(L))` beside a function of `x` is written as two powers of linears

**Answers where there were none, and shorter ones.** `1/(e^(i arctan(a + b x)) x^2)` ran past thirty
seconds: `e^(i arctan(L))` was written `(1 + i L)/sqrt(1 + L^2)`, a root of a quadratic beside the pole.
It is `(1 + i L)^(1/2) (1 - i L)^(-1/2)` as well, for a real `L` -- the two principal powers' arguments are
`arctan(L)/2` each and their moduli cancel -- powers of two linears, and beside a function of `x` it is
written so. Of Rubi's 5.3.6, four integrals are answered that were not, and the 28 answers that change are
a ninth of the length together ([#718](https://github.com/asc-community/AngouriMath/issues/718)).

| Input | Was (2.5.0) | Now |
|---|---|---|
| `"1/(e^(i*atan(a + b*x))*x^2)".ToEntity().Integrate("x")` | `integral(...)`; past thirty seconds on the unreleased master | 340 characters |
| `"x^3/e^(i*atan(a + b*x))".ToEntity().Integrate("x")` | `integral(...)`; past thirty seconds on the unreleased master | 373 characters |
| `"x^3/e^(i*atan(a*x))".ToEntity().Integrate("x")` | `integral(...)`; 25,944 characters on the unreleased master | 218 characters |

### The floor and the ceiling of a rational are exact whatever its size

**Wrong answers fixed.** The floor and the ceiling of an exact rational went through a decimal at the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8549,6 +8549,11 @@ node is Powf(var @base, Number.Rational power) && power is not Number.Integer &&
internal static Entity? SolveByWritingAnExponentialOfAnInverseAlgebraically(Entity expr, Entity.Variable x, bool integrateByParts)
{
var rewrote = false;
// A power of a quadratic in x outside the exponentials, which `(1 + L^2)^(-n/2)` meets.
var quadraticElsewhere = expr.Nodes.Any(node => node is Powf(var q, _) && q.ContainsNode(x) && !q.Nodes.Any(inner => inner is Arctanf or Arcsinf or Arccosf)
&& TreeAnalyzer.TryGetPolyQuadratic(q, x, out var leading, out _, out _) && !TreeAnalyzer.IsZero(leading));
// The variable outside the exponentials.
var xElsewhere = expr.Replace(node => node is Powf(var e, var power) && e == MathS.e && power.ContainsNode(x) ? Number.Integer.One : node).ContainsNode(x);
var rewritten = expr.Replace(node =>
{
if (node is not Powf(var @base, var exponent) || @base != MathS.e || !exponent.ContainsNode(x))
Expand Down Expand Up @@ -8583,6 +8588,20 @@ node is Powf(var @base, Number.Rational power) && power is not Number.Integer &&
// of different orders that nothing reads.
if (inverse is Arctanf)
{
// `(1 + i L)^(n/2) (1 - i L)^(-n/2)`: the two principal powers' arguments are
// `(n/2) arctan(L)` each and their moduli cancel, for a real L, so it is
// `e^(n i arctan(L))` exactly, powers of two linears, which the rules for a
// product of linear powers read. For n = 1 or -1 beside a function of x and no
// power of a quadratic in x for the other form to meet: `e^(i arctan(a + b x))/x^2`
// was `(1 + i L)/sqrt(1 + L^2)` over `x^2`, a root of a quadratic beside a pole, and
// ran past thirty seconds, and `x^3 e^(-i arctan(a x))` came out in 26 thousand
// characters where so it is 218. Alone the exponential is answered shorter as the
// root, and for a power not whole the quotient's power is.
if ((n == Number.Integer.One || n == Number.Integer.MinusOne) && !quadraticElsewhere && xElsewhere)
{
var half = Number.Rational.Create(n.ERational.Divide(2));
return MathS.Pow(1 + MathS.i * argument, half) * MathS.Pow(1 - MathS.i * argument, Number.Rational.Create(half.ERational.Negate()));
}
var halfPower = Number.Rational.Create(n.ERational.Negate().Divide(2));
if (n is not Number.Integer)
return MathS.Pow((1 + MathS.i * argument) / (1 - MathS.i * argument), Number.Rational.Create(n.ERational.Divide(2)));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//
// 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>
/// <c>e^(+-i arctan(L))</c> beside a function of <c>x</c>, written as <c>(1 + i L)^(+-1/2) (1 - i L)^(-+1/2)</c>:
/// the two principal powers' arguments are <c>arctan(L)/2</c> each and their moduli cancel, for a real
/// <c>L</c>. Rubi's 5.3.6. The integrands are complex for a real <c>x</c> and are compared as complex numbers.
/// <a href="https://github.com/asc-community/AngouriMath/issues/718">#718</a>
/// </summary>
[Trait("Area", "Calculus")]
public sealed class AnExponentialOfAnArctangentBesideAPowerIntegralTest
{
[Theory]
[InlineData("1/(e^(i*atan(a + b*x))*x^2)")]
[InlineData("x^3/e^(i*atan(a + b*x))")]
[InlineData("x^3/e^(i*atan(a*x))")]
[InlineData("e^(i*atan(a*x))*x^2")]
public void AsTwoPowersOfLinears(string integrand)
{
var integral = integrand.ToEntity().Integrate("x");
var text = integral.Stringize();
Assert.DoesNotContain("integral(", text);
Assert.True(text.Length < 5000, $"{text.Length} characters of answer for {integrand}");
Entity Pinned(Entity e) => e.Substitute("a", 1.3).Substitute("b", 0.7);
var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x");
var original = Pinned(integrand.ToEntity());
var compared = 0;
foreach (var at in new[] { -1.2, -0.7, 0.3, 0.8, 1.3, 2.9 })
{
var want = original.Substitute("x", at).EvalNumerical();
var got = derivative.Substitute("x", at).EvalNumerical();
if (want.IsNaN)
continue;
compared++;
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}");
}
Assert.True(compared >= 5, $"only {compared} points could be compared for {integrand}");
}
}
}
Loading