diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md
index 0f1494e17..6dc4bb0d0 100644
--- a/BREAKING-CHANGES.md
+++ b/BREAKING-CHANGES.md
@@ -1109,6 +1109,28 @@ with `int F` the next power over `p^2`. Rubi's 6.1.1, 6.2.1, 6.5.1 and 6.6.1
| `"x/sech(x)^(7/2)-5/21*x*sqrt(sech(x))".Integrate("x")` | left unevaluated | the antiderivative, over two reduction steps |
| `"x/csch(x)^(3/2)+1/3*x*sqrt(csch(x))".Integrate("x")` | left unevaluated | the antiderivative |
+### A hyperbolic function of a logarithm is integrated, the exponent folded structurally
+
+`tanh(ln(x))` was left as written. The library spells `tanh(y)` with `e^(2y)`, so a hyperbolic
+function of a logarithm is an exponential whose exponent is a *sum* holding one logarithm --
+`e^(a + b ln(q))` -- and the rule that folds an exponential of a logarithm read only a product,
+`e^(k ln(q))`. It reads the exponent structurally now: `e^(u + v)` is `e^u e^v`, `e^(k u)` is
+`(e^u)^k` for an `x`-free `k`, `e^(u/d)` likewise, and `e^(ln q)` is `q`, so
+`a + b ln(c x^n)` folds to `e^a (c x^n)^b` and its negation -- which the same function writes
+below the bar -- to the reciprocal. Composed exponents are flattened as they fold: `n (ln(q)/2)`
+is `q^(n/2)` and not `(sqrt(q))^n`, whose nesting made
+`e^(n acoth(a x))/(c - a^2 c x^2)^4` a search of fifty seconds where the flat form is declined in
+three. One logarithm in the exponent, since a difference of two folds to a power of a quotient of
+quotients that nothing below reads. Rubi's 6.3.2 and 6.5.3
+([#718](https://github.com/asc-community/AngouriMath/issues/718)).
+
+| Input | Was (2.5.0) | Now |
+|---|---|---|
+| `"tanh(ln(x))".Integrate("x")` | left unevaluated | `x - 2 arctan(x)` up to the form |
+| `"sinh(2+3*ln(x))".Integrate("x")` | left unevaluated | `e^2 x^4/8 - x^(-2)/(4 e^2)` up to the form |
+| `"sech(a+2*ln(c/x^(1/2)))^3".Integrate("x")` | left unevaluated | the antiderivative |
+| `"x*tanh(a+2*ln(x))^2".Integrate("x")` | left unevaluated | the antiderivative |
+
### `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 0499ba134..7c8cf4439 100644
--- a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
+++ b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
@@ -9877,27 +9877,78 @@ node is Powf(Powf(var @base, var inner), var outer)
{
if (node is not Powf(var @base, var exponent) || @base != MathS.e || !exponent.ContainsNode(x))
return node;
- // The exponent as a product with one natural logarithm of x among its factors
- // and nothing else of x: `3 * (1/2 * ln(q))` is how `e^(3 acoth(a x))` arrives.
- Entity? argument = null;
- Entity k = Number.Integer.One;
- foreach (var factor in Mulf.LinearChildren(exponent))
- {
- if (factor is Logf(var logBase, var inner) && logBase == MathS.e && argument is null)
- argument = inner;
- else if (factor.ContainsNode(x))
- return node;
- else
- k = k * factor;
- }
- if (argument is null)
+ // The exponent read structurally, since `e^(u + v)` is `e^u e^v`, `e^(k u)` is
+ // `(e^u)^k` and `e^(ln q)` is `q`: `a + b ln(c x^n)` -- a hyperbolic function of
+ // a logarithm -- folds to `e^a (c x^n)^b`, and its negation, which the same
+ // function writes below the bar, to the reciprocal of that.
+ // One logarithm in the exponent: `a + b ln(c x^n)` is a hyperbolic function of
+ // a logarithm, and `n acoth(a x)` written as a difference of two -- which folds
+ // to a power of a quotient of quotients -- was a search of fifty seconds where
+ // the unfolded form is declined in three.
+ if (exponent.Nodes.Count(inner => inner is Logf(var logBase, _) && logBase == MathS.e) != 1)
return node;
- var power = k.InnerSimplified;
- return power == Number.Integer.One ? argument : MathS.Pow(argument, power);
+ var folded = FoldTheExponent(exponent, x);
+ return folded ?? node;
});
return folded == expr ? null : Integration.ComputeAsAQuestionOfItsOwn(folded, x, integrateByParts);
}
+ ///
+ /// e^(exponent) written without the exponential wherever the exponent is built
+ /// from logarithms and constants: e^(u + v) is e^u e^v, e^(k u) is
+ /// (e^u)^k for an -free k, and e^(ln q) is
+ /// q. where a part mentioning is
+ /// none of those, and where no logarithm was folded at all.
+ ///
+ private static Entity? FoldTheExponent(Entity exponent, Entity.Variable x)
+ {
+ var folded = Fold(exponent, out var found);
+ return found ? folded : null;
+
+ Entity? Fold(Entity exponent, out bool found)
+ {
+ found = false;
+ switch (exponent)
+ {
+ case Logf(var logBase, var inner) when logBase == MathS.e:
+ found = true;
+ return inner;
+ case Sumf(var left, var right):
+ {
+ var foldedLeft = Fold(left, out var leftFound);
+ var foldedRight = Fold(right, out var rightFound);
+ found = leftFound || rightFound;
+ return foldedLeft is null || foldedRight is null ? null : foldedLeft * foldedRight;
+ }
+ case Minusf(var left, var right):
+ {
+ var foldedLeft = Fold(left, out var leftFound);
+ var foldedRight = Fold(right, out var rightFound);
+ found = leftFound || rightFound;
+ return foldedLeft is null || foldedRight is null ? null : foldedLeft / foldedRight;
+ }
+ case Mulf(var left, var right) when !left.ContainsNode(x):
+ return Raised(Fold(right, out found), left);
+ case Mulf(var left, var right) when !right.ContainsNode(x):
+ return Raised(Fold(left, out found), right);
+ case Divf(var above, var below) when !below.ContainsNode(x):
+ return Raised(Fold(above, out found), (Number.Integer.One / below).InnerSimplified);
+ default:
+ // A part free of the variable stays an exponential of itself.
+ return exponent.ContainsNode(x) ? null : MathS.Pow(MathS.e, exponent);
+ }
+ }
+
+ // The power of a power as one power: `n (1/2 ln q)` is `q^(n/2)` and not
+ // `(sqrt(q))^n`, whose nesting the rules below read as a different question --
+ // `e^(n acoth(a x))/(c - a^2 c x^2)^4` was a search of fifty seconds written that
+ // way and is declined in three written flat.
+ static Entity? Raised(Entity? folded, Entity power)
+ => folded is null ? null
+ : folded is Powf(var @base, var inner) ? MathS.Pow(@base, (inner * power).InnerSimplified)
+ : MathS.Pow(folded, power);
+ }
+
///
/// A logarithm whose argument is a quotient in that cancels with
/// the functions of in it taken for indeterminates, with the
diff --git a/Sources/Tests/UnitTests/Calculus/ExponentialOfALogarithmIntegralTest.cs b/Sources/Tests/UnitTests/Calculus/ExponentialOfALogarithmIntegralTest.cs
index 0adf3706e..f2a3f0490 100644
--- a/Sources/Tests/UnitTests/Calculus/ExponentialOfALogarithmIntegralTest.cs
+++ b/Sources/Tests/UnitTests/Calculus/ExponentialOfALogarithmIntegralTest.cs
@@ -76,5 +76,19 @@ private static void DifferentiatesBack(string integrand)
[InlineData("e^(ln(x^2 + 1)/2) * x")]
[InlineData("e^(2*(1/2*ln(x + 2)))")]
public void AnExponentialOfAMultipleOfALogarithm(string integrand) => DifferentiatesBack(integrand);
+
+ ///
+ /// The exponent read structurally, since e^(u + v) is e^u e^v and
+ /// e^(k u) is (e^u)^k: a hyperbolic function of a logarithm is written
+ /// with e^(a + b ln(q)) above the bar and e^(-(a + b ln(q))) below it,
+ /// and both are powers of q times a constant. Rubi's 6.5.3 and 6.6.3.
+ ///
+ [Theory]
+ [InlineData("sinh(2 + 3*ln(x))")]
+ [InlineData("cosh(1 + ln(x^2 + 1))")]
+ [InlineData("sech(3 + 2*ln(2/x^(1/2)))^3")]
+ [InlineData("e^(1 + ln(x + 2)/2)")]
+ [InlineData("tanh(ln(x))")]
+ public void AHyperbolicFunctionOfALogarithm(string integrand) => DifferentiatesBack(integrand);
}
}