From b43641264c158b48110364d7b0363ce9dece321f Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Wed, 7 Oct 2026 06:12:03 +0000 Subject: [PATCH] An odd power of the secant is read in the tangent, with the cosine's sign The substitution u = tan(x) read an odd power of the sine or the cosine as its sign times a function of the tangent, and not the secant, the same the other way up. Part of #718. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura --- BREAKING-CHANGES.md | 14 ++++++++++++++ .../Integration/IndefiniteIntegralSolver.cs | 5 +++++ .../Calculus/TangentSubstitutionIntegralTest.cs | 15 ++++++++++++++- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md index be218cd26..937b3f87c 100644 --- a/BREAKING-CHANGES.md +++ b/BREAKING-CHANGES.md @@ -270,6 +270,20 @@ answer on the far side of a root gets a real expression where it used to get a c | `1/(x*(-4+x^2)^4)` | 8,472 ms | 1,878 ms | | `1/((1+x)^3*(2+x)^3)` | 1,343 ms | 492 ms | +### An odd power of the secant is read in the tangent, with the cosine's sign + +**Answers where there were none.** `sec(x)^5/(a + b tan(x))^2` was declined: the substitution +`u = tan(x)` read an odd power of the sine or the cosine as its sign times a function of the tangent, +`cos(x) = sgn(cos(x))/sqrt(1 + u^2)`, and not the secant, which is the same the other way up. It reads the +secant too now, and the integrand is `sgn(cos(x)) (1 + u^2)^(3/2)/(a + b u)^2` in `u` +([#718](https://github.com/asc-community/AngouriMath/issues/718)). + +| Input | Was (2.5.0) | Now | +|---|---|---| +| `"sec(x)^5/(a + b*tan(x))^2".ToEntity().Integrate("x")` | `integral(...)` | in `sgn(cos(x))` and `tan(x)`, 901 characters | +| `"sec(x)^7/(a + b*tan(x))^3".ToEntity().Integrate("x")` | `integral(...)` | 1,253 characters | +| `"sec(x)/(a + b*cot(x))".ToEntity().Integrate("x")` | `integral(...)` | 571 characters | + ### A whole power of the radicand under Euler's substitution is read as one **Answers where there were none, and none where they were wrong.** Euler's substitution writes the diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs index 97b29a3d2..887db8f3d 100644 --- a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs +++ b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs @@ -10283,6 +10283,11 @@ static bool IsTwice(Entity argument, Entity.Variable x) => MathS.Pow(sign / rootOfSecantSquared, k), Powf(Sinf(var a), Number.Integer k) when a == x && k.EInteger.CanFitInInt32() && !k.EInteger.IsEven => MathS.Pow(sign * tangent / rootOfSecantSquared, k), + // And the secant is the cosine the other way up, the sign its own inverse: + // `sec(x)^5/(a + b tan(x))^2` is `sgn(cos(x)) (1 + u^2)^(5/2)/(a + b u)^2`. + Secantf(var a) when a == x => sign * rootOfSecantSquared, + Powf(Secantf(var a), Number.Integer k) when a == x && k.EInteger.CanFitInInt32() && !k.EInteger.IsEven + => MathS.Pow(sign * rootOfSecantSquared, k), _ => node, }).Substitute(tangent, uSub); if (odd.ContainsNode(x) || !IsAlgebraicIn(odd, uSub)) diff --git a/Sources/Tests/UnitTests/Calculus/TangentSubstitutionIntegralTest.cs b/Sources/Tests/UnitTests/Calculus/TangentSubstitutionIntegralTest.cs index 4f1d43468..73be89a65 100644 --- a/Sources/Tests/UnitTests/Calculus/TangentSubstitutionIntegralTest.cs +++ b/Sources/Tests/UnitTests/Calculus/TangentSubstitutionIntegralTest.cs @@ -113,7 +113,20 @@ private static void DifferentiatesBack(string integrand) [InlineData("sqrt(a + b*csc(c + d*x)^2)")] [InlineData("sqrt(1 + csc(x)^2)")] [InlineData("1/sqrt(-1 + csc(x)^2)")] - public void AnEvenPowerOfTheSecantOrTheCosecantUnderARoot(string integrand) + public void AnEvenPowerOfTheSecantOrTheCosecantUnderARoot(string integrand) => DifferentiatesBackWithTheSymbolsPinned(integrand); + + /// + /// An odd power of the secant is the cosine's the other way up: sec(x)^5/(a + b tan(x))^2 + /// is sgn(cos(x)) (1 + u^2)^(3/2)/(a + b u)^2 under u = tan(x). Rubi's 4.3.1.2, + /// checked on both signs of the cosine. + /// + [Theory] + [InlineData("sec(x)^5/(a + b*tan(x))^2")] + [InlineData("sec(x)^7/(a + b*tan(x))^3")] + [InlineData("sec(c + d*x)^5/(a + b*tan(c + d*x))^3")] + public void AnOddPowerOfTheSecantIsItsSignTimesAFunctionOfTheTangent(string integrand) => DifferentiatesBackWithTheSymbolsPinned(integrand); + + private static void DifferentiatesBackWithTheSymbolsPinned(string integrand) { var integral = integrand.ToEntity().Integrate("x"); Assert.DoesNotContain("integral(", integral.Stringize());