Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

/// <summary>
/// <c>e^(exponent)</c> written without the exponential wherever the exponent is built
/// from logarithms and constants: <c>e^(u + v)</c> is <c>e^u e^v</c>, <c>e^(k u)</c> is
/// <c>(e^u)^k</c> for an <paramref name="x"/>-free <c>k</c>, and <c>e^(ln q)</c> is
/// <c>q</c>. <see langword="null"/> where a part mentioning <paramref name="x"/> is
/// none of those, and where no logarithm was folded at all.
/// </summary>
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);
}

/// <summary>
/// A logarithm whose argument is a quotient in <paramref name="x"/> that cancels with
/// the functions of <paramref name="x"/> in it taken for indeterminates, with the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);

/// <summary>
/// The exponent read structurally, since <c>e^(u + v)</c> is <c>e^u e^v</c> and
/// <c>e^(k u)</c> is <c>(e^u)^k</c>: a hyperbolic function of a logarithm is written
/// with <c>e^(a + b ln(q))</c> above the bar and <c>e^(-(a + b ln(q)))</c> below it,
/// and both are powers of <c>q</c> times a constant. Rubi's 6.5.3 and 6.6.3.
/// </summary>
[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);
}
}
Loading