From 3bf0a1f1da9a20ea3779c399e98fc2cf70f76dff Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Mon, 28 Sep 2026 17:45:32 +0000 Subject: [PATCH] A quadratic divided through by its leading coefficient is read as a multiple of the radicand `x/((1 - a^2 x^2)^2 artanh(a x))` ran out of time. Under `x = tanh(u)/a` a whole power of a constant multiple of `1 - a^2 x^2` is written as that power of `sech(u)^2`, but the integrand reaches the substitution with the quadratic divided through by its leading coefficient, `1/(-a^2) + x^2`, and the multiple was read from the simplified quotient of the two, which does not simplify free of `x`. The substitution then left `(4 a^2 cosh(u)^2 - 4 a^2 sinh(u)^2)^2` below the bar, a constant written in exponentials, and the search in `u` ran out of budget. The two are proportional (checked at sampled points first), so the multiple is the ratio of their leading coefficients, which is now what is read where the quotient does not simplify. The inverse trigonometric substitution reads through the same helper: `1/((c + a^2 c x^2)^3 arctan(a x))` arrives as `c^0 a^(-2) + x^2`. Rubi's problems whose answer uses Si, Ci, Shi or Chi (1186, 3 s): 857 to 900, all 43 in 7.3.4 and all of them timeouts before, none lost, 0 wrong. Part of #1501. Co-Authored-By: Claude Opus 5.5 --- BREAKING-CHANGES.md | 13 +++++++++++++ .../Integration/IndefiniteIntegralSolver.cs | 8 ++++++++ .../Calculus/HyperbolicIntegralIntegrationTest.cs | 15 +++++++++++++++ .../TrigonometricIntegralIntegrationTest.cs | 1 + 4 files changed, 37 insertions(+) diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md index edd19a65c..1d9746658 100644 --- a/BREAKING-CHANGES.md +++ b/BREAKING-CHANGES.md @@ -1790,6 +1790,19 @@ to a constant ([#1501](https://github.com/asc-community/AngouriMath/issues/1501) | `"sinh(x)^2/x".Integrate("x")` | `integral(((e ^ x - e ^ (-x)) / 2) ^ 2 / x, x)` | `-1/2 * ln(x) + 1/2 * Chi(2 * x) + C` | | `"cosh(a+b*x)/(c+d*x)".Integrate("x")` | `integral((e ^ (a + b * x) + e ^ (-(a + b * x))) / 2 / (c + d * x), x)` | `Chi` and `Shi` of `b (c + d x)/d`, with `cosh(a - b c/d)/d` and `sinh(a - b c/d)/d` in front, written in exponentials | +### An inverse hyperbolic tangent over a power of `1 - a^2 x^2` is integrated to the hyperbolic sine and cosine integrals + +`x/((1 - a^2 x^2)^2 artanh(a x))` ran out of time. Under `x = tanh(u)/a` it is +`sinh(u) cosh(u)/(a^2 u)`, but the quadratic reached the substitution divided through by its +leading coefficient, as `1/(-a^2) + x^2`, and was not recognised as a multiple of `1 - a^2 x^2`. It +is now, and these integrate to `Shi` and `Chi` of `2 artanh(a x)` +([#1501](https://github.com/asc-community/AngouriMath/issues/1501)). + +| Input | Was (2.5.0) | Now | +|---|---|---| +| `"x/((1-a^2*x^2)^2*atanh(a*x))".Integrate("x")` | `integral(x / ((1 - a ^ 2 * x ^ 2) ^ 2 * 1/2 * ln((1 + a * x) / (1 - a * x))), x)` | `Shi(2 artanh(a x))/(2 a^2)`, with `artanh` written as its logarithm | +| `"1/((1-a^2*x^2)^2*atanh(a*x))".Integrate("x")` | `integral(1 / ((1 - a ^ 2 * x ^ 2) ^ 2 * 1/2 * ln((1 + a * x) / (1 - a * x))), x)` | `(ln(artanh(a x)) + Chi(2 artanh(a x)))/(2 a)`, likewise | + ### A definite integral is the limit at a bound where its antiderivative is undefined `integral(x * e^(-x), x, 0, +oo)` was `NaN`, this library's way of saying a value does not diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs index a9a3024a9..be067898d 100644 --- a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs +++ b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs @@ -5586,6 +5586,14 @@ node is Powf(var @base, Number.Rational power) && power is not Number.Integer && if (!AreProportionalAtSampledPoints(candidate, wanted, x)) return null; var ratio = Functions.PartialFractions.Bare((candidate / wanted).Simplify()); + // Two proportional quadratics whose quotient does not simplify free of x: the + // integrand's `1 - a^2 x^2` arrives divided through by its leading coefficient, as + // `1/(-a^2) + x^2`, and the ratio is that of the leading coefficients. + if (ratio.ContainsNode(x) + && TreeAnalyzer.TryGetPolyQuadratic(candidate, x, out var candidateLeading, out _, out _) + && TreeAnalyzer.TryGetPolyQuadratic(wanted, x, out var wantedLeading, out _, out _) + && !TreeAnalyzer.IsZero(wantedLeading)) + ratio = Functions.PartialFractions.Bare((candidateLeading / wantedLeading).Simplify()); if (ratio.ContainsNode(x) || ratio.Nodes.Any(node => node == MathS.NaN)) return null; // A multiple that is known negative is refused: `sqrt(k Q)` is `sqrt(k) sqrt(Q)` diff --git a/Sources/Tests/UnitTests/Calculus/HyperbolicIntegralIntegrationTest.cs b/Sources/Tests/UnitTests/Calculus/HyperbolicIntegralIntegrationTest.cs index c95628726..984e30132 100644 --- a/Sources/Tests/UnitTests/Calculus/HyperbolicIntegralIntegrationTest.cs +++ b/Sources/Tests/UnitTests/Calculus/HyperbolicIntegralIntegrationTest.cs @@ -67,6 +67,21 @@ private static readonly (string, string)[] Pins = public void ASumOfExponentialsOverAPowerOfALinear(string integrand) => DifferentiatesBack(integrand, AroundZero, Pins); + /// + /// An inverse hyperbolic tangent below the bar, beside a whole power of 1 - a^2 x^2: + /// under x = tanh(u)/a it is a polynomial in sinh(u) and cosh(u) over + /// a power of u. The quadratic reaches the substitution divided through by its + /// leading coefficient, as 1/(-a^2) + x^2, and is read as a multiple of + /// 1 - a^2 x^2 by the ratio of the two leading coefficients. Rubi's 7.3.4, + /// x^m/((1 - a^2 x^2)^k artanh(a x)^p). + /// + [Theory] + [InlineData("x/((1 - a^2*x^2)^2*atanh(a*x))")] + [InlineData("1/((1 - a^2*x^2)^2*atanh(a*x))")] + [InlineData("x^2/((1 - a^2*x^2)^3*atanh(a*x)^2)")] + public void AnInverseHyperbolicTangentBelowTheBar(string integrand) + => DifferentiatesBack(integrand, AroundZero, Pins); + [Theory] [InlineData("sinh(x)/x", "Shi(x)")] [InlineData("cosh(x)/x", "Chi(x)")] diff --git a/Sources/Tests/UnitTests/Calculus/TrigonometricIntegralIntegrationTest.cs b/Sources/Tests/UnitTests/Calculus/TrigonometricIntegralIntegrationTest.cs index 042565e3e..ef129c110 100644 --- a/Sources/Tests/UnitTests/Calculus/TrigonometricIntegralIntegrationTest.cs +++ b/Sources/Tests/UnitTests/Calculus/TrigonometricIntegralIntegrationTest.cs @@ -135,6 +135,7 @@ public void UnderAPowerOfTheVariable(string integrand) [InlineData("1/acos(x)")] [InlineData("sqrt(1 - x^2)/asin(x)")] [InlineData("x/((c + d^2*c*x^2)^2*atan(d*x))")] + [InlineData("1/((c + d^2*c*x^2)^3*atan(d*x))")] public void ThroughAnInverseTrigonometricFunction(string integrand) => DifferentiatesBack(integrand, new[] { 0.15, 0.3, 0.5, 0.7 }, Pins);