From 322b50ec39a424406b2fcca92af45a9dc90f3b0c Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Sun, 4 Oct 2026 08:25:01 +0000 Subject: [PATCH 1/2] Half-odd powers of a + i a sinh are integrated by the half angle at which they are squares MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit x^3 sqrt(a + i a sinh(e + f x)) was declined, with the rest of Rubi's 6.1.1 and 6.1.5 that put a half-odd power of a ± i a sinh beside a power of x. 1 + i sinh(y) is (cosh(y/2) + i sinh(y/2))^2, so such a power is a^p times an odd power of cosh(y/2) ± i sinh(y/2) up to a constant on every interval where both are continuous. The rest of the integrand is written in the half angle and asked again, and the answer is the antiderivative times the power as written over that form. Part of #718. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura --- BREAKING-CHANGES.md | 16 +++ .../Integration/IndefiniteIntegralSolver.cs | 107 ++++++++++++++++++ .../Integration/Integration.Definition.cs | 2 + ...usAnImaginaryHyperbolicSineIntegralTest.cs | 47 ++++++++ 4 files changed, 172 insertions(+) create mode 100644 Sources/Tests/UnitTests/Calculus/OnePlusAnImaginaryHyperbolicSineIntegralTest.cs diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md index e9ae2c6a1..614d49545 100644 --- a/BREAKING-CHANGES.md +++ b/BREAKING-CHANGES.md @@ -246,6 +246,22 @@ of the third to the sixth degree, with a symbol in it, that written in `y = x + | `"1/(3*a*b + 3*b^2*x + 3*b*c*x^2 + c^2*x^3)".ToEntity().Integrate("x")`, and its square | `integral(...)` | two logarithms and an arctangent in `x + b/c` | | `"x/(a + 8*x - 8*x^2 + 4*x^3 - x^4)".ToEntity().Integrate("x")`, and `1` over it | `integral(...)` | the antiderivative in `x - 1` | +### Half-odd powers of `a + i a sinh` are integrated by the half angle at which they are squares + +**Answers where there were none.** `x^3 sqrt(a + i a sinh(e + f x))` was declined, with the rest of +the 32 of Rubi's 6.1.1 and 6.1.5 that put a half-odd power of `a ± i a sinh` beside a power of `x`, +six of them after searches past the budget. `1 + i sinh(y)` is `(cosh(y/2) + i sinh(y/2))^2`, so +such a power is `a^p` times an odd power of `cosh(y/2) ± i sinh(y/2)`, a sum of exponentials of the +half angle, up to a constant on every interval where both are continuous; it is integrated so now, +and the answer is the antiderivative times the power as written over that form, which holds on every +such interval whatever `a` is ([#718](https://github.com/asc-community/AngouriMath/issues/718)). + +| Input | Was (2.5.0) | Now | +|---|---|---| +| `"x^3*sqrt(a + i*a*sinh(e + f*x))".ToEntity().Integrate("x")` | `integral(...)` | powers of `x` times exponentials of the half angle | +| `"sqrt(a + i*a*sinh(e + f*x))/x".ToEntity().Integrate("x")` | `integral(...)` | exponential integrals of the half angle | +| `"1/sqrt(a + i*a*sinh(e + f*x))".ToEntity().Integrate("x")` | `integral(...)` | arctangents and logarithms of `e^((e + f x)/2)` | + ### The hyperbolic functions have antiderivatives, and so does anything rational in `e^(k x)` An integrand rational in `e^(k x)` becomes a rational function of one variable under diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs index 9965d1608..83750e49b 100644 --- a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs +++ b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs @@ -20836,6 +20836,113 @@ private static (Entity OverTheTwo, Entity Argument)? ReadTheHyperbolicFunctions( return answer.Nodes.Any(node => node == MathS.NaN) ? null : answer; } + /// + /// Half-odd powers of a ± i a sinh(y) beside anything in the hyperbolic functions of + /// y, by the half angle at which they are squares: 1 + i sinh(y) is + /// (cosh(y/2) + i sinh(y/2))^2, so sqrt(a + i a sinh(y)) is + /// sqrt(a) (cosh(y/2) + i sinh(y/2)) times a constant on every interval where both + /// are continuous. The rest of the integrand is written in the half angle, and the question + /// asked again in x. + /// + /// + /// + /// Rubi's x^3 sqrt(a + i a sinh(e + f x)) and the rest of the 47 of 6.1.1 and 6.1.5 + /// were declined or searches past the budget: the half angle of + /// reads + /// a ± a cosh(y), and 1 + i sinh(y) is the square of a complex function rather + /// than of a real one. + /// + /// + /// The constant is not written: the answer is the antiderivative of the rewritten integrand + /// times each power as written over the form it was rewritten to, a quotient whose + /// logarithmic derivative is zero, so it is constant wherever it is continuous and the + /// answer holds on every such interval, whatever a is. + /// https://github.com/asc-community/AngouriMath/issues/718 + /// + /// + internal static Entity? SolveAHalfOddPowerOfOnePlusAnImaginaryHyperbolicSine(Entity expr, Entity.Variable x, bool integrateByParts) + { + var s = Variable.CreateUnique(expr, "s_hyp"); + var c = Variable.CreateUnique(expr, "c_hyp"); + if (ReadTheHyperbolicFunctions(expr, x, s, c) is not var (read, argument)) + return null; + var half = (argument / 2).InnerSimplified; + var sinhHalf = MathS.Hyperbolic.Sinh(half); + var coshHalf = MathS.Hyperbolic.Cosh(half); + Entity constant = Number.Integer.One; + var found = false; + var rewritten = read.Replace(node => + { + if (node is not Powf(var radicand, Number.Rational exponent) || exponent is Number.Integer + || !exponent.ERational.Denominator.Equals(EInteger.FromInt32(2)) + || !radicand.ContainsNode(s) || radicand.ContainsNode(c) + || ReadAsOnePlusMinusAnImaginarySine(radicand, s) is not var (a, plus)) + return node; + found = true; + var root = plus ? coshHalf + MathS.i * sinhHalf : coshHalf - MathS.i * sinhHalf; + var written = MathS.Pow(a, exponent) * MathS.Pow(root, Number.Integer.Create(exponent.ERational.Numerator)); + var asItIs = MathS.Pow(radicand.Substitute(s, MathS.Hyperbolic.Sinh(argument)), exponent); + constant = constant * asItIs / written; + return written; + }); + if (!found) + return null; + var inX = rewritten.Substitute(c, 2 * MathS.Sqr(coshHalf) - 1).Substitute(s, 2 * sinhHalf * coshHalf); + if (inX.ContainsNode(s) || inX.ContainsNode(c)) + return null; + if (Integration.ComputeAsTheSameQuestion(inX, x, integrateByParts) is not { } result + || result.Nodes.Any(node => node == MathS.NaN)) + return null; + return constant * result; + } + + /// + /// read as a (1 ± i s) for the hyperbolic sine + /// : the constant a, and whether the imaginary unit comes + /// with a plus. Null for anything else. + /// + private static (Entity Constant, bool Plus)? ReadAsOnePlusMinusAnImaginarySine(Entity radicand, Entity sine) + { + Entity a = Number.Integer.Zero; + Entity? b = null; + foreach (var term in Sumf.LinearChildren(radicand)) + { + if (!term.ContainsNode(sine)) + { + a += term; + continue; + } + if (b is not null) + return null; + Entity coefficient = Number.Integer.One; + var seen = false; + foreach (var factor in Mulf.LinearChildren(term)) + { + if (factor == sine && !seen) + seen = true; + else if (!factor.ContainsNode(sine)) + coefficient *= factor; + else + return null; + } + if (!seen) + return null; + b = coefficient; + } + if (b is null) + return null; + a = a.InnerSimplified; + if (a.Evaled is Number.Complex { IsZero: true }) + return null; + static bool IsZero(Entity value) => value.InnerSimplified.Evaled is Number.Complex { IsZero: true } + || value.Simplify().Evaled is Number.Complex { IsZero: true }; + if (IsZero(b - MathS.i * a)) + return (a, true); + if (IsZero(b + MathS.i * a)) + return (a, false); + return null; + } + /// /// A sum every term of which carries the same power of one linear form in /// , written as that power times the sum of the rest: diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs b/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs index 8cae2ee5f..38fa7155c 100644 --- a/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs +++ b/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs @@ -812,6 +812,8 @@ private static Entity Normalized(Entity expr, Entity.Variable x) => if ((answer = IndefiniteIntegralSolver.SolveByTheHalfAngleTangentBesideAHalfOddPowerOfOnePlusASecant(expr, x, integrateByParts)) is { }) return answer; // And `a ± a cosh(y)` under a fractional power: `2a cosh(y/2)^2`, `-2a sinh(y/2)^2`. if ((answer = IndefiniteIntegralSolver.SolveByTheHalfAngleWhereOnePlusAHyperbolicCosineIsASquare(expr, x, integrateByParts)) is { }) return answer; + // The hyperbolic sine's, off the real line: 1 + i sinh(y) is (cosh(y/2) + i sinh(y/2))^2. + if ((answer = IndefiniteIntegralSolver.SolveAHalfOddPowerOfOnePlusAnImaginaryHyperbolicSine(expr, x, integrateByParts)) is { }) return answer; // Several trigonometric arguments that are multiples of one linear with an offset or a // symbolic slope, written in that linear: before the substitution search, which reads // each function on its own. diff --git a/Sources/Tests/UnitTests/Calculus/OnePlusAnImaginaryHyperbolicSineIntegralTest.cs b/Sources/Tests/UnitTests/Calculus/OnePlusAnImaginaryHyperbolicSineIntegralTest.cs new file mode 100644 index 000000000..c727ae764 --- /dev/null +++ b/Sources/Tests/UnitTests/Calculus/OnePlusAnImaginaryHyperbolicSineIntegralTest.cs @@ -0,0 +1,47 @@ +// +// 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 +{ + /// + /// Half-odd powers of a + i a sinh(y), which is a (cosh(y/2) + i sinh(y/2))^2: + /// beside a power of x each is a sum of exponentials of the half angle times that power, + /// up to a constant on every interval where both are continuous. Rubi's 6.1.1 and 6.1.5. The + /// integrands are complex, and compared as complex numbers on both sides of zero. + /// #718 + /// + [Trait("Area", "Calculus")] + public sealed class OnePlusAnImaginaryHyperbolicSineIntegralTest + { + [Theory] + [InlineData("x^3*sqrt(a + i*a*sinh(g + f*x))")] + [InlineData("x*sqrt(a + i*a*sinh(g + f*x))")] + [InlineData("sqrt(a + i*a*sinh(g + f*x))/x")] + [InlineData("x^3*(a + i*a*sinh(g + f*x))^(3/2)")] + [InlineData("1/sqrt(a + i*a*sinh(g + f*x))")] + public void ByTheHalfAngle(string integrand) + { + var integral = integrand.ToEntity().Integrate("x"); + Assert.DoesNotContain("integral(", integral.Stringize()); + Entity Pinned(Entity e) => e.Substitute("a", 1.3).Substitute("g", 0.4).Substitute("f", 1.1); + var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x"); + var original = Pinned(integrand.ToEntity()); + foreach (var at in new[] { -1.2, -0.4, 0.3, 0.8, 1.5 }) + { + var want = original.Substitute("x", at).EvalNumerical(); + var got = derivative.Substitute("x", at).EvalNumerical(); + 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}"); + } + } + } +} From 061478e1feea06b56e6512ae6459e0b2c5eea37b Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Sun, 4 Oct 2026 16:40:32 +0000 Subject: [PATCH 2/2] The a + i a sinh rows name their constant g, a symbol, as the test does Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura --- BREAKING-CHANGES.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md index 445597fd1..72ed18c4a 100644 --- a/BREAKING-CHANGES.md +++ b/BREAKING-CHANGES.md @@ -284,19 +284,19 @@ of the third to the sixth degree, with a symbol in it, that written in `y = x + ### Half-odd powers of `a + i a sinh` are integrated by the half angle at which they are squares -**Answers where there were none.** `x^3 sqrt(a + i a sinh(e + f x))` was declined, with the rest of -the 32 of Rubi's 6.1.1 and 6.1.5 that put a half-odd power of `a ± i a sinh` beside a power of `x`, -six of them after searches past the budget. `1 + i sinh(y)` is `(cosh(y/2) + i sinh(y/2))^2`, so -such a power is `a^p` times an odd power of `cosh(y/2) ± i sinh(y/2)`, a sum of exponentials of the -half angle, up to a constant on every interval where both are continuous; it is integrated so now, -and the answer is the antiderivative times the power as written over that form, which holds on every -such interval whatever `a` is ([#718](https://github.com/asc-community/AngouriMath/issues/718)). +**Answers where there were none.** `x^3 sqrt(a + i a sinh(g + f x))` was declined, with the rest of +Rubi's 6.1.1 and 6.1.5 with a half-odd power of `a ± i a sinh`, six of them after searches past the +budget. `1 + i sinh(y)` is `(cosh(y/2) + i sinh(y/2))^2`, so such a power is `a^p` times an odd +power of `cosh(y/2) ± i sinh(y/2)`, a sum of exponentials of the half angle, up to a constant on +every interval where both are continuous; it is integrated so now, and the answer is the +antiderivative times the power as written over that form, which holds on every such interval +whatever `a` is ([#718](https://github.com/asc-community/AngouriMath/issues/718)). | Input | Was (2.5.0) | Now | |---|---|---| -| `"x^3*sqrt(a + i*a*sinh(e + f*x))".ToEntity().Integrate("x")` | `integral(...)` | powers of `x` times exponentials of the half angle | -| `"sqrt(a + i*a*sinh(e + f*x))/x".ToEntity().Integrate("x")` | `integral(...)` | exponential integrals of the half angle | -| `"1/sqrt(a + i*a*sinh(e + f*x))".ToEntity().Integrate("x")` | `integral(...)` | arctangents and logarithms of `e^((e + f x)/2)` | +| `"x^3*sqrt(a + i*a*sinh(g + f*x))".ToEntity().Integrate("x")` | `integral(...)` | powers of `x` times exponentials of the half angle | +| `"sqrt(a + i*a*sinh(g + f*x))/x".ToEntity().Integrate("x")` | `integral(...)` | `Shi` and `Chi` of half of `f x` | +| `"1/sqrt(a + i*a*sinh(g + f*x))".ToEntity().Integrate("x")` | `integral(...)` | arctangents and logarithms of `e^((g + f x)/2)` | ### The hyperbolic functions have antiderivatives, and so does anything rational in `e^(k x)`