From 997bb77412315659559e5400cda50f33a3d58430 Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Tue, 13 Oct 2026 04:23:52 +0000 Subject: [PATCH 1/3] A trigonometric of a logarithm of an imaginary power is written in a named constant times a power Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura --- .../Integration/IndefiniteIntegralSolver.cs | 64 ++++++++++++++++--- 1 file changed, 55 insertions(+), 9 deletions(-) diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs index 8c828130a..9dbcf742e 100644 --- a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs +++ b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs @@ -26893,8 +26893,16 @@ private static (Entity Factor, Entity Inside)? TryTakeACommonLinearFactorOfASum( { if (!expr.Nodes.Any(node => node is Logf && node.ContainsNode(x))) return null; + // `e^(i L)` is `K x^p` for a real `p` when `u` is a product of constants and powers of + // the variable, with `K = e^(i L) x^(-p)` constant wherever it is defined: named, the + // integrand is rational in `x` with one symbol in it, where `e^(i a)` and `e^(-i a)`, or + // `c^(2 i)` and `c^(-2 i)`, were two that never cancelled and answered a piecewise of + // thousands of characters. One argument only, so that one name stands for it. + var arguments = new HashSet(); + Entity? power = null; + var named = Variable.CreateUnique(expr, "k_exp"); var any = false; - var rewritten = expr.Replace(node => + Entity Rewritten(bool naming) => expr.Replace(node => { var (argument, kind) = node switch { @@ -26906,11 +26914,14 @@ private static (Entity Factor, Entity Inside)? TryTakeACommonLinearFactorOfASum( Cosecantf(var of) => (of, 5), _ => ((Entity?)null, -1) }; - if (argument is null || !IsLinearInALogarithmWithAnImaginaryCoefficient(argument, x)) + if (argument is null || !IsLinearInALogarithmWithAnImaginaryCoefficient(argument, x, out var itsPower)) return node; any = true; - var plus = MathS.Pow(MathS.e, MathS.i * argument); - var minus = MathS.Pow(MathS.e, -MathS.i * argument); + arguments.Add(argument); + power = itsPower; + var (plus, minus) = naming && itsPower is { } + ? (named * MathS.Pow(x, itsPower), MathS.Pow(x, -itsPower) / named) + : (MathS.Pow(MathS.e, MathS.i * argument), MathS.Pow(MathS.e, -MathS.i * argument)); return kind switch { 0 => (plus - minus) / (2 * MathS.i), @@ -26921,6 +26932,7 @@ private static (Entity Factor, Entity Inside)? TryTakeACommonLinearFactorOfASum( _ => 2 * MathS.i / (plus - minus), }; }); + var rewritten = Rewritten(naming: true); if (!any) return null; // Beside its own derivative the logarithm is a substitution's: `tan(a + i ln(x))/x` is @@ -26935,15 +26947,26 @@ private static (Entity Factor, Entity Inside)? TryTakeACommonLinearFactorOfASum( if (beside.ContainsNode(x) && AreProportionalAtSampledPoints(beside, logarithm.Differentiate(x), x)) return null; } - return Integration.ComputeAsTheSameQuestion(rewritten, x, integrateByParts); + // A condition on `K` is a sign of a number that is not real, and has no value once + // `K` is written back: `tan(a + i ln(x))`'s antiderivative is a piecewise on `K^4 > 0`. + // There the exponentials are asked as they are. + if (power is { } && arguments.Count == 1 + && Integration.ComputeAsTheSameQuestion(rewritten, x, integrateByParts) is { } answer + && !answer.Nodes.Any(node => node is Providedf(_, var condition) && condition.ContainsNode(named) + || node is Piecewise piecewise && piecewise.Cases.Any(@case => @case.Predicate.ContainsNode(named)))) + return answer.Substitute(named, (MathS.Pow(MathS.e, MathS.i * arguments.First()) * MathS.Pow(x, -power)).InnerSimplified); + return Integration.ComputeAsTheSameQuestion(Rewritten(naming: false), x, integrateByParts); } /// /// Whether is a + b ln(u), with u the only place the - /// variable is and b an imaginary number. + /// variable is and b an imaginary number, or u a product of constants and + /// powers of the variable whose powers b makes imaginary. is + /// then the real p of e^(i L) = K x^p, and null for any other u. /// - private static bool IsLinearInALogarithmWithAnImaginaryCoefficient(Entity argument, Entity.Variable x) + private static bool IsLinearInALogarithmWithAnImaginaryCoefficient(Entity argument, Entity.Variable x, out Entity? power) { + power = null; var logarithms = argument.Nodes .Where(node => node is Logf(var @base, var of) && @base == MathS.e && of.ContainsNode(x)) .Distinct().ToList(); @@ -26958,10 +26981,33 @@ private static bool IsLinearInALogarithmWithAnImaginaryCoefficient(Entity argume // A number, and not a symbol's: with `b = sqrt(-1/n^2)` the power of the variable this // leaves is `1/x` for every positive n, which nothing reading `n` symbolically can know, // and the general power's formula comes back with a zero below its bar. - return coefficient.Vars.Count() == 0 && coefficient.Evaled is Number.Complex number && number is not Number.Real - && System.Math.Abs((double)number.RealPart) < 1e-12 * System.Math.Abs((double)number.ImaginaryPart); + if (coefficient.Vars.Any()) + return false; + // `2 ln(c x^(i/2))`: the imaginary factor is in the logarithm's power of the variable. + // What makes `e^(i b ln(u))` a power of the variable is that `b x u'/u` is a constant, + // and it is `i` there. For `u` a product of constants and powers of the variable, + // `x u'/u` is the sum of those powers, read off the factors. + Entity sum = Number.Integer.Zero; + foreach (var (factor, underneath) in FactorsOfTheIntegrand(((Logf)logarithms[0]).Antilogarithm)) + { + Entity? its = factor == x ? Number.Integer.One + : factor is Powf(var @base, var exponent) && @base == x && !exponent.ContainsNode(x) ? exponent + : !factor.ContainsNode(x) ? Number.Integer.Zero + : null; + if (its is null) + return IsAnImaginaryNumber(coefficient); + sum = underneath ? sum - its : sum + its; + } + if (!IsAnImaginaryNumber(coefficient * sum)) + return false; + power = (MathS.i * coefficient * sum).InnerSimplified; + return true; } + private static bool IsAnImaginaryNumber(Entity expr) + => expr.Vars.Count() == 0 && expr.Evaled is Number.Complex number && number is not Number.Real + && System.Math.Abs((double)number.RealPart) < 1e-12 * System.Math.Abs((double)number.ImaginaryPart); + /// /// A power of the variable times a sine or cosine of a logarithm, in closed form: /// int x^m sin(L) dx is x^(m + 1)((m + 1) sin(L) - B cos(L))/((m + 1)^2 + B^2) From 1d3c0f8b989d05c8e11f97ac6be883582ab9ba11 Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Tue, 13 Oct 2026 04:27:34 +0000 Subject: [PATCH 2/3] Test an imaginary power in the logarithm on both signs of c Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura --- ...etricOfAnImaginaryLogarithmIntegralTest.cs | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/Sources/Tests/UnitTests/Calculus/TrigonometricOfAnImaginaryLogarithmIntegralTest.cs b/Sources/Tests/UnitTests/Calculus/TrigonometricOfAnImaginaryLogarithmIntegralTest.cs index 1e33f74c0..00cef4f30 100644 --- a/Sources/Tests/UnitTests/Calculus/TrigonometricOfAnImaginaryLogarithmIntegralTest.cs +++ b/Sources/Tests/UnitTests/Calculus/TrigonometricOfAnImaginaryLogarithmIntegralTest.cs @@ -45,10 +45,33 @@ public void BesideItsOwnDerivativeByTheSubstitution(string integrand) DifferentiatesBack(integrand, integral); } - private static void DifferentiatesBack(string integrand, Entity integral) + /// + /// The imaginary factor in the logarithm's power of the variable, 2 ln(c x^(i/2)): + /// e^(i L) is a constant K times x^p for the real p = i b x u'/u, + /// and with K named the integrand is rational in x. Unnamed, c^(2 i) + /// and c^(-2 i) never cancelled and the answer was a piecewise of 6,000 characters. + /// K is e^(i L) x^(-p), constant wherever it is defined, for either sign of + /// c. + /// + [Theory] + [InlineData("sec(a + 2*ln(c*x^(1/2*i)))^3", 1.3)] + [InlineData("sec(a + 2*ln(c*x^(1/2*i)))^3", -1.3)] + [InlineData("csc(a + 2*ln(c*x^(1/2*i)))^3", 1.3)] + [InlineData("x*sec(a + 2*ln(c*x^i))^3", 1.3)] + [InlineData("x*csc(a + 2*ln(c*x^i))^3", -1.3)] + [InlineData("sec(a + 2*ln(c/x^(1/2*i)))^3", 1.3)] + [InlineData("sec(a + 2*ln(c/x^(1/2*i)))^3", -1.3)] + public void AnImaginaryPowerInTheLogarithm(string integrand, double c) + { + var integral = integrand.ToEntity().Integrate("x"); + Assert.True(integral.Stringize().Length <= 600, $"{integral.Stringize().Length} characters"); + DifferentiatesBack(integrand, integral, c); + } + + private static void DifferentiatesBack(string integrand, Entity integral, double c = 1.3) { Assert.DoesNotContain("integral(", integral.Stringize()); - Entity Pinned(Entity e) => e.Substitute("a", 0.4).Substitute("c", 1.3); + Entity Pinned(Entity e) => e.Substitute("a", 0.4).Substitute("c", c); var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x"); var original = Pinned(integrand.ToEntity()); foreach (var at in new[] { 0.3, 0.8, 1.5, 2.4 }) From e0444ef7cc3e07306fe8e5cc310b927fefa89f00 Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Tue, 13 Oct 2026 04:28:27 +0000 Subject: [PATCH 3/3] A secant of a logarithm of an imaginary power in BREAKING-CHANGES Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura --- BREAKING-CHANGES.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md index 38f06d56b..299924a02 100644 --- a/BREAKING-CHANGES.md +++ b/BREAKING-CHANGES.md @@ -2200,6 +2200,22 @@ number; the zero is a power `1/x`, whose integral is a logarithm. A symbolic `b` | `"sin(a + ln(c*x^2)*sqrt(-1/4))".ToEntity().Integrate("x")` | `integral(...)` | powers of `x` and `c x^2` and a logarithm, through `e^(i a)` | | `"1/cos(a - 2*i*ln(c*x))^(3/2)".ToEntity().Integrate("x")` | `integral(...)` | an arctangent and a logarithm of a root, through `e^(i a)` | +### A secant or cosecant of a logarithm of an imaginary power is integrated in a named constant + +**Answers where there were none.** `sec(a + 2 ln(c x^(i/2)))^3` was declined, with `x sec(a + 2 ln(c x^i))^3` and the +cosecant's, the imaginary factor being in the logarithm's power of the variable rather than its coefficient (Rubi's +4.7.5). `e^(i L)` is a constant `K` times `x^p` for the real `p = i b x u'/u`, with `K = e^(i L) x^(-p)` constant +wherever it is defined, for either sign of `c`. With `K` named the integrand is rational in `x`; the same question +asked without naming it answered a piecewise of over 6,000 characters, `c^(2 i)` and `c^(-2 i)` never cancelling +([#718](https://github.com/asc-community/AngouriMath/issues/718)). + +| Input | Was (2.5.0) | Now | +|---|---|---| +| `"sec(a + 2*ln(c*x^(1/2*i)))^3".ToEntity().Integrate("x")` | `integral(...)` | 262 characters | +| `"csc(a + 2*ln(c*x^(1/2*i)))^3".ToEntity().Integrate("x")` | `integral(...)` | 264 characters | +| `"x*sec(a + 2*ln(c*x^i))^3".ToEntity().Integrate("x")` | `integral(...)` | 275 characters, and so the cosecant's | +| `"sec(a + 2*ln(c/x^(1/2*i)))^3".ToEntity().Integrate("x")` | `integral(...)` | 484 characters | + ### A constant plus an imaginary cosine and sine is an exponential **Answers where there were none.** `(A + B cos(x))/(a + b cos(x) + i b sin(x))` was declined, with the