From 60d1b8976c57d145e74f739c309f826724f33aa4 Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Sat, 17 Oct 2026 20:28:17 +0000 Subject: [PATCH 1/2] Read an exponential of an inverse below the bar as a negative multiple x^2/(e^(i arctan(a x)) (c + a^2 c x^2)^(3/2)) wrote the exponential as (1 + i a x)/sqrt(1 + a^2 x^2) below the bar, a linear with i in it the rational rules do not read there. Taken above the bar with its exponent negated, a negative whole multiple is written over the conjugate, (1 - i L)^(-n) (1 + L^2)^(n/2): x^2 (1 - i a x)/(c^(3/2) (1 + a^2 x^2)^2), which is answered (Rubi's 5.3.6:513). Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura --- .../Integration/IndefiniteIntegralSolver.cs | 25 ++++++++ ...alOfAnArctangentBelowTheBarIntegralTest.cs | 57 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 Sources/Tests/UnitTests/Calculus/AnExponentialOfAnArctangentBelowTheBarIntegralTest.cs diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs index d1fbe9ec7..f1b149946 100644 --- a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs +++ b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs @@ -9691,6 +9691,21 @@ node is Powf(var @base, Number.Rational power) && power is not Number.Integer && /// internal static Entity? SolveByWritingAnExponentialOfAnInverseAlgebraically(Entity expr, Entity.Variable x, bool integrateByParts) { + // An exponential below the bar taken above it with its exponent negated, so that a + // negative multiple is read as one: `x^2/(e^(i arctan(a x)) (c + a^2 c x^2)^(3/2))` is + // `x^2 e^(-i arctan(a x))/(c + a^2 c x^2)^(3/2)`, which is written over the conjugate. + if (expr is Divf(var overIt, var underIt) && Mulf.LinearChildren(underIt).Any(IsAnExponentialOfAnInverse)) + { + Entity kept = Number.Integer.One, raised = Number.Integer.One; + foreach (var factor in Mulf.LinearChildren(underIt)) + if (IsAnExponentialOfAnInverse(factor) && factor is Powf(_, var power)) + raised *= MathS.Pow(MathS.e, -power); + else + kept *= factor; + expr = overIt * raised / kept; + } + bool IsAnExponentialOfAnInverse(Entity node) => node is Powf(var e0, var power0) && e0 == MathS.e && power0.ContainsNode(x) + && power0.Nodes.Any(inner => inner is Arctanf or Arcsinf or Arccosf); 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) @@ -9759,6 +9774,16 @@ node is Powf(var @base, Number.Rational power) && power is not Number.Integer && 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))); + // A negative n over the conjugate, `(1 + i L)^(-1)` being `(1 - i L)/(1 + L^2)`: + // the linear with `i` in it is then above the bar, where the rational rules read + // it, and `x^2/((1 + i a x)(1 + a^2 x^2))` beside it was left unevaluated where + // `x^2 (1 - i a x)/(1 + a^2 x^2)^2` is answered. + if (n is Number.Integer { IsNegative: true }) + { + var conjugatePower = Number.Integer.Create(((Number.Integer)n).EInteger.Negate()); + return (conjugatePower == Number.Integer.One ? 1 - MathS.i * argument : MathS.Pow(1 - MathS.i * argument, conjugatePower)) + * MathS.Pow(1 + MathS.Sqr(argument), Number.Rational.Create(n.ERational.Divide(2))); + } return (n == Number.Integer.One ? 1 + MathS.i * argument : MathS.Pow(1 + MathS.i * argument, n)) * MathS.Pow(1 + MathS.Sqr(argument), halfPower); } Entity unit = inverse is Arcsinf diff --git a/Sources/Tests/UnitTests/Calculus/AnExponentialOfAnArctangentBelowTheBarIntegralTest.cs b/Sources/Tests/UnitTests/Calculus/AnExponentialOfAnArctangentBelowTheBarIntegralTest.cs new file mode 100644 index 000000000..6dc905867 --- /dev/null +++ b/Sources/Tests/UnitTests/Calculus/AnExponentialOfAnArctangentBelowTheBarIntegralTest.cs @@ -0,0 +1,57 @@ +// +// 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 +{ + /// + /// An exponential of i arctan(a x) below the bar, taken above it as a negative multiple and + /// written over the conjugate: Rubi's 5.3.6 x^2/(e^(i arctan(a x)) (c + a^2 c x^2)^(3/2)), + /// which was left unevaluated. + /// #718 + /// + [Trait("Area", "Calculus")] + public sealed class AnExponentialOfAnArctangentBelowTheBarIntegralTest + { + 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("x^2/(e^(i*atan(a*x))*(c+a^2*c*x^2)^(3/2))")] + [InlineData("x/(e^(i*atan(a*x))*(c+a^2*c*x^2)^(3/2))")] + [InlineData("1/(e^(i*atan(a*x))*(c+a^2*c*x^2)^(3/2))")] + public void IsAnsweredAndDifferentiatesBack(string integrand) + { + DifferentiatesBack(integrand, ("a", 1.3), ("c", 0.7)); + DifferentiatesBack(integrand, ("a", -0.5), ("c", 2.5)); + } + } +} From 5a754f4e9101edc25ce664384836cc8d43c9a202 Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Sun, 18 Oct 2026 00:52:45 +0000 Subject: [PATCH 2/2] Record the exponentials of i arctan below the bar in BREAKING-CHANGES Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura --- BREAKING-CHANGES.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md index d1451be9d..534d41cf7 100644 --- a/BREAKING-CHANGES.md +++ b/BREAKING-CHANGES.md @@ -595,6 +595,21 @@ 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 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 +below the bar was read as `n = 1`. It is taken above the bar with its exponent negated, and for a negative whole `n`, +`e^(n i arctan(L))` is written over the conjugate, `(1 - i L)^(-n) (1 + L^2)^(n/2)`, which puts the linear with `i` in +it above the bar where the rational rules read it +([#718](https://github.com/asc-community/AngouriMath/issues/718)). + +| Input | Was (2.5.0) | Now | +|---|---|---| +| `"x^2/(e^(i*atan(a*x))*(c+a^2*c*x^2)^(3/2))".ToEntity().Integrate("x")` | `integral(...)` | 211 characters | +| `"x/(e^(i*atan(a*x))*(c+a^2*c*x^2)^(3/2))".ToEntity().Integrate("x")` | `integral(...)` | 109 characters | +| `"1/(e^(i*atan(a*x))*(c+a^2*c*x^2)^(3/2))".ToEntity().Integrate("x")` | `integral(...)` | 132 characters | +| `"x^2/(e^(5*i*atan(a*x))*(c+a^2*c*x^2)^(27/2))".ToEntity().Integrate("x")` | `integral(...)` | 189 characters | + ### A symbol shared by a numerator sum's coefficients is taken out before the partial fractions **Answers where there were none.** `(b d + 2c d x)^9/(a + b x + c x^2)^3` ran past a minute, where