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
Original file line number Diff line number Diff line change
Expand Up @@ -22156,17 +22156,35 @@ private static (Entity Constant, Entity Base, Entity ExponentInU, Variable U, En
/// exponential of the product: <c>(e^x)^(1/3)</c> is <c>e^(x/3)</c> and <c>(3^(3x))^(1/4)</c>
/// is <c>3^(3x/4)</c>, exactly, since the base is positive; and it is only in that
/// spelling that the exponential rules read them. Timofeev's
/// <c>(cos(x/2) + sin(x/2))/(e^x)^(1/3)</c> and <c>cos(3x/2)/(3^(3x))^(1/4)</c>.
/// <c>(cos(x/2) + sin(x/2))/(e^x)^(1/3)</c> and <c>cos(3x/2)/(3^(3x))^(1/4)</c>. And a whole
/// power of a constant times one, <c>(-e^(-b x))^2</c>, as the constant's power times the
/// exponential of the multiple, whatever the constant is.
/// </summary>
internal static Entity? SolveByFlatteningAPowerOfAnExponential(Entity expr, Entity.Variable x, bool integrateByParts)
{
var flattened = expr.Replace(node =>
node is Powf(Powf(var @base, var inner), var outer)
&& !@base.ContainsNode(x) && inner.ContainsNode(x) && !outer.ContainsNode(x)
&& (@base == MathS.e || @base.Evaled is Number.Real { IsPositive: true })
&& outer.Evaled is Number.Real
? MathS.Pow(@base, (outer * inner).InnerSimplified)
: node);
bool IsAnExponential(Entity @base, Entity inner) =>
!@base.ContainsNode(x) && inner.ContainsNode(x)
&& (@base == MathS.e || @base.Evaled is Number.Real { IsPositive: true });
// A whole power of a constant times an exponential: (k E)^n is k^n E^n for every k and
// E when n is whole, so (-e^(-b x))^2 is e^(-2 b x). The product of two of them, which
// sinh(b x)^3 sinh(d x)^3 expands into, is read by nothing else.
Entity? Distributed(Entity left, Entity right, Number.Integer whole) =>
(left, right) switch
{
(Powf(var b, var p), var k) when !k.ContainsNode(x) && IsAnExponential(b, p) =>
MathS.Pow(k, whole) * MathS.Pow(b, (whole * p).InnerSimplified),
(var k, Powf(var b, var p)) when !k.ContainsNode(x) && IsAnExponential(b, p) =>
MathS.Pow(k, whole) * MathS.Pow(b, (whole * p).InnerSimplified),
_ => null
};
var flattened = expr.Replace(node => node switch
{
Powf(Powf(var @base, var inner), var outer)
when IsAnExponential(@base, inner) && !outer.ContainsNode(x) && outer.Evaled is Number.Real =>
MathS.Pow(@base, (outer * inner).InnerSimplified),
Powf(Mulf(var left, var right), Number.Integer whole) => Distributed(left, right, whole) ?? node,
_ => node
});
// The same question in another spelling, asked as one of its own, so that the
// closed rules that answer only at the top -- the exponential times a
// trigonometric -- are consulted for it.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//
// 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
{
/// <summary>
/// A whole power of a constant times an exponential, <c>(k e^u)^n = k^n e^(n u)</c>. The terms of
/// <c>sinh(a + b x)^3 sinh(c + d x)^3</c>, written in exponentials, are products of two of them,
/// <c>(-e^(-b x))^2 (-e^(-d x))^2</c>, which nothing else read: 2.5.0 answered the product, and
/// 2.6.0's development had stopped. Rubi's 6.7.1.
/// <a href="https://github.com/asc-community/AngouriMath/issues/718">#718</a>
/// </summary>
[Trait("Area", "Calculus")]
public sealed class AWholePowerOfAMultipleOfAnExponentialIntegralTest
{
[Theory]
[InlineData("(-e^(-b*x))^2*(-e^(-d*x))^2")]
[InlineData("(-e^(-b*x))^2")]
[InlineData("(2*e^x)^3")]
[InlineData("sinh(b*x)^3*sinh(d*x)^3")]
[InlineData("sinh(a + b*x)^3*sinh(c + d*x)^3")]
public void AsAnExponentialOfTheMultiple(string integrand)
{
var integral = integrand.ToEntity().Integrate("x");
var text = integral.Stringize();
Assert.DoesNotContain("integral(", text);
Assert.True(text.Length < 5000, $"{text.Length} characters of answer for {integrand}");
Entity Pinned(Entity e) => e.Substitute("a", 1.3).Substitute("b", 0.7).Substitute("c", 0.4).Substitute("d", 0.3);
var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x");
var original = Pinned(integrand.ToEntity());
var compared = 0;
foreach (var at in new[] { -1.2, -0.7, 0.3, 0.8, 1.3, 2.9 })
{
var want = original.Substitute("x", at).EvalNumerical();
var got = derivative.Substitute("x", at).EvalNumerical();
if (want.IsNaN)
continue;
compared++;
Assert.True(Math.Abs((double)(got - want).RealPart) + Math.Abs((double)(got - want).ImaginaryPart)
< 1e-9 * Math.Max(1, Math.Abs((double)want.RealPart) + Math.Abs((double)want.ImaginaryPart)),
$"d/dx of the antiderivative of {integrand} is {got} at x = {at}, where the integrand is {want}");
}
Assert.True(compared >= 5, $"only {compared} points could be compared for {integrand}");
}
}
}
Loading