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);