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 @@ -608,6 +608,19 @@ no numeric root finder applies, and its discriminant vanishes identically. Such
| `"1/(x^3-3*b*x+2*b^(3/2))".ToEntity().Integrate("x")` | `integral(...)` | 122 characters |
| `"1/(-9*b*x+9*x^3+2*b^(3/2)*sqrt(3))".ToEntity().Integrate("x")` | `integral(...)` | 176 characters |

### An exponential of an arctangent beside a power of its quadratic is answered where it is an exact derivative

**Answers where there were none.** `e^(i n arctan(a x)) x^2 (c + a^2 c x^2)^(-1 - n^2/2)` was left unevaluated: no rule
reads a polynomial beside the exponential and a symbolic power of `c + a^2 c x^2`. Where the integrand is the
derivative of `e^(N arctan(a x)) (α + β x) (c + a^2 c x^2)^(p + 1)` for a quadratic polynomial beside it, the two
coefficients are solved for and that is the answer, checked by differentiating it back
([#718](https://github.com/asc-community/AngouriMath/issues/718)).

| Input | Was (2.5.0) | Now |
|---|---|---|
| `"e^(i*n*atan(a*x))*x^2*(c+a^2*c*x^2)^(-1-n^2/2)".ToEntity().Integrate("x")` | `integral(...)` | 148 characters |
| `"e^(2*atan(x))*(3+8/3*x+5/3*x^2)*(1+x^2)^(-2/3)".ToEntity().Integrate("x")` | `integral(...)` | `e ^ (2 * arctan(x)) * (1 + x) * (1 + x ^ 2) ^ (1/3) + C` |

### An exponential of i arctan below the bar is read as a negative multiple

**Answers where there were none.** `x^2/(e^(i arctan(a x)) (c + a^2 c x^2)^(3/2))` was left unevaluated: the exponential
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9746,6 +9746,69 @@ node is Powf(var @base, Number.Rational power) && power is not Number.Integer &&
return ratio;
}

/// <summary>
/// An exponential of a multiple of <c>arctan(a x)</c> times a quadratic polynomial times a
/// power of <c>c + a^2 c x^2</c>, where it is an exact derivative:
/// <c>(e^(N arctan(a x)) (alpha + beta x) Q^s)'</c> is
/// <c>c e^(N arctan(a x)) Q^(s - 1) (a N alpha + beta + (a N beta + 2 s a^2 alpha) x + a^2 beta (1 + 2 s) x^2)</c>
/// for <c>Q = c + a^2 c x^2</c>, since <c>Q^s/(1 + a^2 x^2) = c Q^(s - 1)</c>. The
/// constant and squared coefficients give <c>alpha</c> and <c>beta</c>; the linear one is
/// the condition. Rubi's 5.3.6:504, <c>e^(i n arctan(a x)) x^2 (c + a^2 c x^2)^(-1 - n^2/2)</c>,
/// meets it exactly, and was left unevaluated: as powers of the two linears its exponents
/// do not sum to a whole number.
/// https://github.com/asc-community/AngouriMath/issues/718
/// </summary>
internal static Entity? SolveAnExactDerivativeOfAnExponentialOfAnArctangent(Entity expr, Entity.Variable x)
{
Entity? multiple = null, slope = null, quadratic = null, power = null;
Entity polynomial = Number.Integer.One;
foreach (var factor in Mulf.LinearChildren(expr))
{
if (factor is Powf(var e, var exponent) && e == MathS.e && exponent.ContainsNode(x))
{
if (multiple is not null)
return null;
var inverse = exponent.Nodes.OfType<Arctanf>().FirstOrDefault();
if (inverse is null || !TreeAnalyzer.TryGetPolyLinear(inverse.Argument, x, out var a, out var b) || !TreeAnalyzer.IsZero(b))
return null;
var placeholder = Variable.CreateUnique(exponent, "u_atan");
var inThePlaceholder = exponent.Replace(node => node == inverse ? placeholder : node);
if (inThePlaceholder.ContainsNode(x) || !TreeAnalyzer.TryGetPolyLinear(inThePlaceholder, placeholder, out var n, out var constantPart)
|| !TreeAnalyzer.IsZero(constantPart) || TreeAnalyzer.IsZero(n))
return null;
(multiple, slope) = (n, a);
}
else if (factor is Powf(var q, var p) && !p.ContainsNode(x) && p is not Number.Integer && q.ContainsNode(x))
{
if (quadratic is not null)
return null;
(quadratic, power) = (q, p);
}
else
polynomial *= factor;
}
if (multiple is null || slope is null || quadratic is null || power is null)
return null;
if (!TreeAnalyzer.TryGetPolyQuadratic(quadratic, x, out var c2, out var c1, out var c0) || !TreeAnalyzer.IsZero(c1) || TreeAnalyzer.IsZero(c0)
|| !VanishesIdentically((c2 - MathS.Sqr(slope) * c0).Expand()))
return null;
if (!TreeAnalyzer.TryGetPolyQuadratic(polynomial, x, out var p2, out var p1, out var p0))
return null;
var s = (power + 1).Simplify();
var twice = (1 + 2 * s).Simplify();
if (TreeAnalyzer.IsZero(twice) || TreeAnalyzer.IsZero(p2))
return null;
var beta = (p2 / (c0 * MathS.Sqr(slope) * twice)).Simplify();
var alpha = ((p0 / c0 - beta) / (slope * multiple)).Simplify();
if (!VanishesIdentically((c0 * (slope * multiple * beta + 2 * s * MathS.Sqr(slope) * alpha) - p1).Simplify()))
return null;
var exponential = Mulf.LinearChildren(expr).First(factor => factor is Powf(var e, _) && e == MathS.e && factor.ContainsNode(x));
var candidate = exponential * (alpha + beta * x) * MathS.Pow(quadratic, s);
if (!AreProportionalAtSampledPoints(candidate.Differentiate(x), expr, x))
return null;
return candidate;
}

/// <summary>
/// An exponential of a symbolic multiple of <c>i arctan(L)</c>, <c>L</c> linear, beside
/// powers of multiples of <c>1 + L^2</c>, written as powers of the two linears:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,8 @@ private static Entity WithItsPiecewiseSumsCombined(Entity expr)
// An exponential of i times an inverse trigonometric function written algebraically, at the
// question asked, before the rules that spent the budget: `e^(3 i atan(a + b x))/x^2` ran out of
// time where, rewritten, it is answered in half a second. It is asked again in its place below.
// An exact derivative among them first, closed: `e^(i n arctan(a x)) x^2 (c + a^2 c x^2)^(-1 - n^2/2)`.
if ((answer = IndefiniteIntegralSolver.SolveAnExactDerivativeOfAnExponentialOfAnArctangent(expr, x)) is { }) return answer;
if (AnsweringTheQuestionAsked && (answer = IndefiniteIntegralSolver.SolveByWritingAnExponentialOfAnInverseAlgebraically(expr, x, integrateByParts)) is { }) return answer;
// The same for a symbolic multiple of the arctangent, beside powers of its quadratic.
if (AnsweringTheQuestionAsked && (answer = IndefiniteIntegralSolver.SolveAnExponentialOfASymbolicMultipleOfAnArctangentAsPowersOfTheLinears(expr, x, integrateByParts)) is { }) return answer;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// 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>
/// An exponential of a multiple of <c>arctan(a x)</c> times a quadratic times a power of
/// <c>c + a^2 c x^2</c>, where it is an exact derivative: Rubi's 5.3.6
/// <c>e^(i n arctan(a x)) x^2 (c + a^2 c x^2)^(-1 - n^2/2)</c>, which was left unevaluated.
/// <a href="https://github.com/asc-community/AngouriMath/issues/718">#718</a>
/// </summary>
[Trait("Area", "Calculus")]
public sealed class AnExactDerivativeOfAnExponentialOfAnArctangentIntegralTest
{
private static void DifferentiatesBack(string integrand, params (string, double)[] pins)
{
var integral = integrand.ToEntity().Integrate("x");
Assert.DoesNotContain("integral(", integral.Stringize());

var pinned = integral.Substitute("C", 0);
Entity original = integrand.ToEntity();
foreach (var (name, value) in pins)
{
pinned = pinned.Substitute(name, value);
original = original.Substitute(name, value);
}
var derivative = pinned.Differentiate("x");
foreach (var at in new[] { -2.3, -0.7, 0.4, 1.9 })
{
var got = derivative.Substitute("x", at).EvalNumerical();
var want = original.Substitute("x", at).EvalNumerical();
var difference = Math.Abs((double)(got - want).RealPart) + Math.Abs((double)(got - want).ImaginaryPart);
var scale = Math.Max(1.0, Math.Abs((double)want.RealPart) + Math.Abs((double)want.ImaginaryPart));
Assert.True(difference / scale < 1e-8,
$"d/dx of the antiderivative of {integrand} is {got} at x = {at}, where the integrand is {want}");
}
}

[Theory]
[InlineData("e^(i*n*atan(a*x))*x^2*(c+a^2*c*x^2)^(-1-n^2/2)")]
[InlineData("e^(2*atan(x))*(3+8/3*x+5/3*x^2)*(1+x^2)^(-2/3)")]
public void IsAnsweredAndDifferentiatesBack(string integrand)
{
DifferentiatesBack(integrand, ("a", 1.3), ("c", 0.7), ("n", 0.4));
DifferentiatesBack(integrand, ("a", -0.5), ("c", -1.5), ("n", 2.3));
}
}
}
Loading