diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md
index e392225da..378638426 100644
--- a/BREAKING-CHANGES.md
+++ b/BREAKING-CHANGES.md
@@ -568,6 +568,20 @@ symbol in it and a denominator past a sextic is now left to the partial fraction
| `"(d + e*x^2 + f*x^4)/(x^4*(a + b*x^2 + c*x^4)^2)".ToEntity().Integrate("x")` | `integral(...)`; past a minute on the unreleased master | 3,715 characters |
| `"cos(e + f*x)^5/(a + b*sec(e + f*x)^2)^3".ToEntity().Integrate("x")` | `integral(...)`; past a minute on the unreleased master | 27,944 characters |
+### An exponential of the sine or the cosine beside a polynomial in `x`, the sine and the cosine is integrated
+
+**Answers where there were none.** `e^sin(x) sec(x)^2 (x cos(x)^3 - sin(x))` was declined, Rubi's 4.7.7, and so were
+`e^cos(x) (x sin(x) - 1)` and `e^sin(x) (x cos(x) + 1)`. The ansatz for an exponential beside the trigonometric
+functions read the exponent only when it was linear in `x`; it now also takes an exponent that is a polynomial in
+the sine and the cosine, whose derivative joins each term the ansatz differentiates
+([#718](https://github.com/asc-community/AngouriMath/issues/718)).
+
+| Input | Was (2.5.0) | Now |
+|---|---|---|
+| `"e^sin(x)*sec(x)^2*(x*cos(x)^3 - sin(x))".ToEntity().Integrate("x")` | `integral(...)` | `e ^ sin(x) * (-1 + x * cos(x)) / cos(x)` |
+| `"e^cos(x)*(x*sin(x) - 1)".ToEntity().Integrate("x")` | `integral(...)` | `e ^ cos(x) * -x` |
+| `"e^sin(x)*(x*cos(x) + 1)".ToEntity().Integrate("x")` | `integral(...)` | `e ^ sin(x) * x` |
+
### A symbolic quartic in `x^2` with a square discriminant is split into its two quadratics
**Answers where there were none.** `cot(c + d x)^3 sqrt(a + b sec(c + d x))` ran past a minute: the root of the
diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
index 352cc3792..e07b64d5d 100644
--- a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
+++ b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
@@ -14906,8 +14906,9 @@ bool Read(Entity e, int index, int[] prefix)
///
/// A rational function of x and of sin(x) and cos(x) together, with
- /// an exponential e^(a x) in front or not, closed by the ansatz
- /// F = e^(a x) P/Q with P and Q polynomials in the three.
+ /// an exponential e^h in front or not, h linear in x or a polynomial in
+ /// the three, closed by the ansatz F = e^h P/Q with P and Q polynomials
+ /// in the three.
///
///
///
@@ -14929,6 +14930,12 @@ bool Read(Entity e, int index, int[] prefix)
/// tower first, and every substitution of it leaves powers of 1 + t^2 above and
/// below that nothing cancels; the ring needs no substitution.
///
+ ///
+ /// An exponent in the ring has its derivative there too, so the bracket is
+ /// (h' P Q + P' Q - P Q') D and nothing else changes. Rubi's 4.7.7
+ /// e^sin(x) sec(x)^2 (x cos(x)^3 - sin(x)) is (e^sin(x) (x - sec(x)))' so, a sum
+ /// of two terms neither of which has an elementary antiderivative.
+ ///
/// https://github.com/asc-community/AngouriMath/issues/718
///
internal static Entity? SolveByTrigonometricTowerAnsatz(Entity expr, Entity.Variable x)
@@ -14944,11 +14951,15 @@ bool Read(Entity e, int index, int[] prefix)
if (ReadOneExponentialTimesTheRest(expr, x) is not var (exponent, rest))
return null;
Entity a = Number.Integer.Zero;
+ // Or an exponent that is itself a polynomial in the three, read below: `e^sin(x)`'s
+ // derivative is `cos(x) e^sin(x)`, and the bracket takes `h' m Q` for `a m Q`.
+ var curved = false;
if (exponent is not null)
{
- if (!TreeAnalyzer.TryGetPolyLinear(exponent, x, out var slope, out _) || slope.ContainsNode(x))
- return null;
- a = slope;
+ if (TreeAnalyzer.TryGetPolyLinear(exponent, x, out var slope, out _) && !slope.ContainsNode(x))
+ a = slope;
+ else
+ curved = true;
}
var overTheTwo = rest.Replace(node => node switch
{
@@ -14994,6 +15005,23 @@ static bool IsAWholeMultiple(Entity argument, Entity.Variable x, out int k)
var (above, below) = Functions.SingleQuotient.Of(inTheThree);
if (!TrigonometricPolynomial.TryRead(above, x, s, c, out var n) || !TrigonometricPolynomial.TryRead(below, x, s, c, out var d))
return null;
+ TrigonometricPolynomial? exponentPrime = null;
+ if (curved)
+ {
+ var exponentInTheThree = exponent!.Replace(node =>
+ {
+ if (node is Sinf(var argument) && IsAWholeMultiple(argument, x, out var k))
+ return MultipleAngle(k, s, c).Sine;
+ if (node is Cosf(var argument2) && IsAWholeMultiple(argument2, x, out var k2))
+ return MultipleAngle(k2, s, c).Cosine;
+ return node;
+ });
+ if (exponentInTheThree.Nodes.Any(node => node is Sinf or Cosf && node.ContainsNode(x))
+ || !TrigonometricPolynomial.TryRead(exponentInTheThree, x, s, c, out var h)
+ || h.DegreeInX > MaximumTrigonometricTowerDegree || h.TrigonometricDegree > MaximumTrigonometricTowerDegree)
+ return null;
+ exponentPrime = h.Derivative();
+ }
if (n.DegreeInX > MaximumTrigonometricTowerDegree || d.DegreeInX > MaximumTrigonometricTowerDegree
|| n.TrigonometricDegree > MaximumTrigonometricTowerDegree || d.TrigonometricDegree > MaximumTrigonometricTowerDegree)
return null;
@@ -15037,6 +15065,8 @@ static bool IsAWholeMultiple(Entity argument, Entity.Variable x, out int k)
var bracket = m.Derivative().Times(q).Minus(m.Times(qPrime));
if (a.Evaled is not Number.Complex { IsZero: true })
bracket = bracket.Plus(m.Times(q).Scaled(a));
+ if (exponentPrime is not null)
+ bracket = bracket.Plus(m.Times(q).Times(exponentPrime));
columns.Add(bracket.Times(d));
monomialsOfP.Add((i, k, flag));
}
diff --git a/Sources/Tests/UnitTests/Calculus/AnExponentialOfATrigonometricPolynomialIntegralTest.cs b/Sources/Tests/UnitTests/Calculus/AnExponentialOfATrigonometricPolynomialIntegralTest.cs
new file mode 100644
index 000000000..45639a0cd
--- /dev/null
+++ b/Sources/Tests/UnitTests/Calculus/AnExponentialOfATrigonometricPolynomialIntegralTest.cs
@@ -0,0 +1,46 @@
+//
+// 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
+{
+ ///
+ /// An exponential of a polynomial in x, sin(x) and cos(x) beside a
+ /// rational function of the three, closed by the ansatz e^h P/Q:
+ /// e^sin(x) sec(x)^2 (x cos(x)^3 - sin(x)) is (e^sin(x) (x - sec(x)))', though
+ /// neither of its two terms has an elementary antiderivative. Rubi's 4.7.7.
+ /// #718
+ ///
+ [Trait("Area", "Calculus")]
+ public sealed class AnExponentialOfATrigonometricPolynomialIntegralTest
+ {
+ [Theory]
+ [InlineData("e^sin(x)*sec(x)^2*(x*cos(x)^3 - sin(x))", 100)]
+ [InlineData("e^cos(x)*(x*sin(x) - 1)", 100)]
+ [InlineData("e^sin(x)*(x*cos(x) + 1)", 100)]
+ public void DifferentiatesBack(string integrand, int atMost)
+ {
+ var integral = integrand.ToEntity().Integrate("x");
+ var text = integral.Stringize();
+ Assert.DoesNotContain("integral(", text);
+ Assert.True(text.Length < atMost, $"{text.Length} characters of answer for {integrand}");
+ var derivative = integral.Substitute("C", 0).Differentiate("x");
+ var original = integrand.ToEntity();
+ foreach (var at in new[] { "0.35", "1.1", "2.3", "4.4" })
+ {
+ var want = original.Substitute("x", at.ToEntity()).EvalNumerical();
+ var got = derivative.Substitute("x", at.ToEntity()).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)),
+ $"d/dx of the antiderivative of {integrand} is {got} at x = {at}, where the integrand is {want}");
+ }
+ }
+ }
+}