From ecadcd4eb6bca59ac43068ba98c3756217bf33f1 Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Thu, 24 Sep 2026 04:24:28 +0000 Subject: [PATCH] A cos + i A sin below the bar is written as the exponential it is `cos(x)^2/(a cos(x) + i a sin(x))^3` was declined after twelve seconds. `A cos(y) + i A sin(y)` is `A e^(i y)` and `A cos(y) - i A sin(y)` is `A e^(-i y)`; written so, the integrand is an exponential times a power of a cosine, which the closed rules answer at once. As a sum of a cosine and a sine it has no real rotation -- `A^2 + (i A)^2` is zero -- so the rule for `a cos + b sin` has nothing to do with it. The sibling of the rule for `A + i A tan(y)`, and below the bar only for the same reason. A whole power of the product written is split, `(A e^(i y))^n` as `A^n e^(i n y)`: the rule that distributes such powers takes a constant with a symbol in it and leaves a number, and `cos(x)^2/(2 e^(i x))^3` was declined where `cos(x)^2/(a e^(i x))^3` was not -- found by the tests with numeric coefficients after the corpus rows, which are symbolic, had all passed. Rubi's 4.7.2, all 290 problems: 237 to 249, no row lost, 16 timeouts to 14. Families 1, 4, 5, 6 and 7 and the 1774-problem suite unchanged, row for row. Part of #718. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura --- BREAKING-CHANGES.md | 20 ++++++++ .../Integration/IndefiniteIntegralSolver.cs | 48 +++++++++++++++++++ .../Integration/Integration.Definition.cs | 2 + .../Calculus/PolynomialExponentialTrigTest.cs | 33 ++++++++++++- 4 files changed, 102 insertions(+), 1 deletion(-) diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md index 648983e1b..658f31ec2 100644 --- a/BREAKING-CHANGES.md +++ b/BREAKING-CHANGES.md @@ -1371,6 +1371,26 @@ and those rows want partial fractions over the two linear factors instead. Rubi's 4.7.2: 215 to 237 of 290, no row lost, 20 timeouts to 16. +### `A cos + i A sin` below the bar is written as the exponential it is + +`cos(x)^2/(a cos(x) + i a sin(x))^3` was declined after twelve seconds. `A cos(y) + i A sin(y)` is +`A e^(i y)`, and `A cos(y) - i A sin(y)` is `A e^(-i y)`; written so, the integrand is an +exponential times a power of a cosine, which the closed rules answer at once. As a sum of a +cosine and a sine it has no real rotation -- `A^2 + (i A)^2` is zero -- so the rule for +`a cos + b sin` has nothing to do with it. A whole power of the product written is split, +`(A e^(i y))^n` as `A^n e^(i n y)`, since the rule that distributes such powers takes a symbolic +constant and leaves a number: `cos(x)^2/(2 e^(i x))^3` was declined where +`cos(x)^2/(a e^(i x))^3` was not. + +| Input | Was (2.5.0) | Now | +|---|---|---| +| `"cos(x)^2/(a*cos(x)+i*a*sin(x))^3".Integrate("x")` | left unevaluated | exponentials of `-3 i x` times `cos(2x)`, `sin(2x)` | +| `"1/(a*cos(x)+i*a*sin(x))^3".Integrate("x")` | left unevaluated | `a^(-3) e^(-3 i x)/(-3 i)` | + +A secant above the bar is still declined: `sec(x)^2 e^(-3 i x)` is rational in `e^(i x)` with an +imaginary rate, which nothing answers yet. Rubi's 4.7.2: 237 to 249 of 290, no row lost, 16 +timeouts to 14. + ### `binomial(n, k)` is a function **Addition, not silent.** The binomial coefficient is a node, `Entity.Binomialf`, spelled diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs index 57eb7749b..d0b5435e4 100644 --- a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs +++ b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs @@ -15432,6 +15432,54 @@ static bool IsAWholeNumberOfSteps(ERational difference) return rewritten == below ? null : Integration.ComputeAsTheSameQuestion((above / rewritten).InnerSimplified, x, integrateByParts); } + /// + /// A cos(y) + i A sin(y) below the bar, written as the exponential it is: + /// A e^(i y), and A cos(y) - i A sin(y) as A e^(-i y). Beside a power + /// of the cosine above the bar that is an exponential times a power of a cosine, which + /// the closed rules answer at once; as written it is a sum of a cosine and a sine whose + /// coefficients have no real rotation -- A^2 + (i A)^2 is zero -- and + /// cos(x)^2/(a cos(x) + i a sin(x))^3 was declined after twelve seconds. + /// + /// + /// The sibling of , which reads + /// A + i A tan(y); below the bar only, for the same reason. + /// https://github.com/asc-community/AngouriMath/issues/718 + /// + internal static Entity? SolveByWritingAnImaginarySumOfACosineAndASineAsAnExponential(Entity expr, Entity.Variable x, bool integrateByParts) + { + var (above, below) = Functions.SingleQuotient.Of(Functions.SingleQuotient.Combine(expr)); + if (!below.ContainsNode(x)) + return null; + var rewritten = below.Replace(node => + { + if (node is not (Sumf or Minusf) || !node.ContainsNode(x) + || !TryReadACosineAndASine(node, x, out var cosineCoefficient, out var sineCoefficient, out var argument)) + return node; + // The ratio is the imaginary unit one way or the other, and nothing else. Bare: + // `i a/a` simplifies to `i provided not a = 0`, and a condition is not a number + // to compare against. + var ratio = Functions.PartialFractions.Bare((sineCoefficient / cosineCoefficient).InnerSimplified); + if (ratio.Evaled is not Number.Complex) + ratio = Functions.PartialFractions.Bare(ratio.Simplify()); + var plus = ratio.Evaled == MathS.i.Evaled; + if (!plus && ratio.Evaled != (-MathS.i).Evaled) + return node; + return cosineCoefficient * MathS.Pow(MathS.e, ((plus ? MathS.i : -MathS.i) * argument).InnerSimplified); + }); + if (rewritten == below) + return null; + // And a whole power of what was written split, `(A e^(i y))^n` as `A^n e^(i n y)`, so + // that the exponential stands on its own for the rules that read one: the rule that + // distributes such powers takes a constant with a symbol in it and leaves a number, + // and `cos(x)^2/(2 e^(i x))^3` was declined where `cos(x)^2/(a e^(i x))^3` was not. + rewritten = rewritten.Replace(node => + node is Powf(Mulf(var left, var right), Number.Integer power) + && (left is Powf(var leftBase, _) && leftBase == MathS.e || right is Powf(var rightBase, _) && rightBase == MathS.e) + ? MathS.Pow(left, power) * MathS.Pow(right, power) + : node); + return Integration.ComputeAsTheSameQuestion((above / rewritten).InnerSimplified, x, integrateByParts); + } + /// /// Bioche's first two rules for the hyperbolic functions: a rational function of /// sinh(y) and cosh(y) that is odd in the hyperbolic sine is a rational diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs b/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs index cbd0a07ab..ba3cb32b3 100644 --- a/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs +++ b/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs @@ -504,6 +504,8 @@ private static Entity Normalized(Entity expr, Entity.Variable x) => // `A + i A tan(z)` is `A e^(i z)/cos(z)`, which beside a polynomial is a shape the // closed rules answer, where the imaginary unit in the coefficient is read by none. if ((answer = IndefiniteIntegralSolver.SolveByWritingAnImaginaryTangentAsAnExponential(expr, x, integrateByParts)) is { }) return answer; + // And `A cos(z) + i A sin(z)`, which is `A e^(i z)`, where no rotation is real. + if ((answer = IndefiniteIntegralSolver.SolveByWritingAnImaginarySumOfACosineAndASineAsAnExponential(expr, x, integrateByParts)) is { }) return answer; // A fractional power of a perfect square is the power of the modulus, sgn(P) P^(2r). if ((answer = IndefiniteIntegralSolver.SolveByTakingARootOfAPerfectSquare(expr, x, integrateByParts)) is { }) return answer; // x^(n - 1) g(x^n) with a symbolic n is g(u)/n under u = x^n. diff --git a/Sources/Tests/UnitTests/Calculus/PolynomialExponentialTrigTest.cs b/Sources/Tests/UnitTests/Calculus/PolynomialExponentialTrigTest.cs index 234ae44c2..ecebb5c89 100644 --- a/Sources/Tests/UnitTests/Calculus/PolynomialExponentialTrigTest.cs +++ b/Sources/Tests/UnitTests/Calculus/PolynomialExponentialTrigTest.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) 2019-2026 Angouri. // AngouriMath is licensed under MIT. // Details: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md. @@ -263,6 +263,37 @@ public void TheResonanceIsSeenSymbolically(string integrand, string? symbol) [InlineData("(1 + 2*x)/(3 + 3*i*tan(1/2 + x))^2")] public void AnImaginaryTangentBelowTheBarIsAnExponential(string integrand) => DifferentiatesBack(integrand); + /// + /// And its sibling, A cos(y) + i A sin(y), which is A e^(i y): a sum of a + /// cosine and a sine with no real rotation, since A^2 + (i A)^2 is zero, and beside + /// a power of the cosine an exponential times that power once written so. Rubi's 4.7.2, + /// fourteen rows; cos(x)^2/(a cos(x) + i a sin(x))^3 was declined after twelve + /// seconds. + /// + [Theory] + [InlineData("cos(x)^2/(2*cos(x) + 2*i*sin(x))^3")] + [InlineData("cos(x)^5/(2*cos(x) + 2*i*sin(x))^2")] + [InlineData("1/(3*cos(1/2 + x) + 3*i*sin(1/2 + x))^3")] + [InlineData("cos(x)/(2*cos(x) - 2*i*sin(x))")] + public void AnImaginarySumOfACosineAndASineBelowTheBarIsAnExponential(string integrand) => DifferentiatesBack(integrand); + + /// The same with the coefficient a symbol, pinned only after integrating. + [Fact] + public void AnImaginarySumWithASymbolicCoefficient() + { + var integral = "cos(x)^2/(a*cos(x) + i*a*sin(x))^3".ToEntity().Integrate("x"); + Assert.DoesNotContain("integral(", integral.Stringize()); + var derivative = integral.Substitute("C", 0).Substitute("a", 0.9).Differentiate("x"); + var original = "cos(x)^2/(a*cos(x) + i*a*sin(x))^3".ToEntity().Substitute("a", 0.9); + foreach (var at in Points) + { + 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); + Assert.True(difference < 1e-9, $"at x = {at}: {got} for {want}"); + } + } + /// /// A base with symbols in it, and an exponent whose constant part has them too: /// F^(c (a + b x)) leaves F^(a c) as a constant factor, and that factor