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
4 changes: 3 additions & 1 deletion BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,9 @@ as `a - b = 0`, as a statement's own solve reads it: `"x + 1 = 3".Solve("x")` wa
`x^31 e^(-x)` is, whose sum of 32 terms is `-gamma(32, x)` now. A definite integral of such an answer that is
undefined at a bound is left as written. And beside a power of a sine and a cosine, which Euler's formula writes as
those exponentials, the gamma functions of an imaginary argument, and beside a hyperbolic function of a power of
`x`, as `x sinh(c + d x^3)`.
`x`, as `x sinh(c + d x^3)`. A polynomial beside a symbolic power of a logarithm of one shifted linear, or an
exponential of a power of one, is written in that linear, where each term is one of these:
`x (a + b ln(c (d + e x)))^p` and `x^2 f^(c (a + b x)^3)`.
([#2075](https://github.com/asc-community/AngouriMath/issues/2075))

| Input | Was (2.6.0) | Now |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18148,6 +18148,96 @@ bool Read(Entity node, bool insideASum)
return back.Nodes.Any(node => node == MathS.NaN) ? null : back;
}

/// <summary>
/// A polynomial beside a function of one shifted linear <c>a + b x</c> that parts cannot reach, written in
/// <c>u = a + b x</c>: a power that is not whole of something holding a logarithm of it, <c>x (a + b ln(c (d + e x)))^p</c>,
/// or an exponential of a function of it that is not linear, <c>x^2 f^(c (a + b x)^3)</c>. In u the polynomial is one
/// in u, and each of its terms beside the function is answered in the gamma function: <c>u (a + b ln(c u))^p</c> and
/// <c>u^2 f^(c u^3)</c>. Only where the offset is not zero, since in u it is, and this declines there. Rubi's 3.3, 3.4
/// and 2.3. https://github.com/asc-community/AngouriMath/issues/2075
/// </summary>
internal static Entity? SolveAPolynomialBesideATranscendentalPowerOfAShiftedLinear(Entity expr, Entity.Variable x, bool integrateByParts)
{
if (!Integration.AnsweringTheQuestionAskedOrOneBelow || expr is not (Mulf or Divf))
return null;
// The function first, by its shape, before any factor is read as a polynomial: that expands it, and asked of
// every product an algebraic integrand is, it was five per cent of the corpus's time.
Entity? transcendental = null;
foreach (var factor in Mulf.LinearChildren(expr))
if (factor.ContainsNode(x) && IsATranscendentalPowerOfSomethingInX(factor, x))
{
if (transcendental is not null)
return null;
transcendental = factor;
}
if (transcendental is null)
return null;
Entity? polynomial = null;
foreach (var factor in Mulf.LinearChildren(expr))
{
if (!factor.ContainsNode(x) || ReferenceEquals(factor, transcendental))
continue;
if (ThePolynomialIn(factor, x) is not null)
polynomial = polynomial is null ? factor : polynomial * factor;
else
return null;
}
if (transcendental is null || polynomial is null
|| TheOneLinearIn(transcendental, x) is not { } linear
|| !TreeAnalyzer.TryGetPolyLinear(linear, x, out var slope, out var offset)
|| slope.ContainsNode(x) || offset.ContainsNode(x) || TreeAnalyzer.IsZero(slope) || VanishesIdentically(offset))
return null;
// x = (u - a)/b, so that the function is of u, and dx = du/b: the whole integrand, its constants with it.
var u = Variable.CreateUnique(expr, "u_linear");
if (transcendental.Replace(node => node == linear ? u : node).ContainsNode(x))
return null;
var inU = expr.Replace(node => node == linear ? u : node).Substitute(x, (u - offset) / slope);
if (inU.ContainsNode(x)
|| Integration.ComputeAsAQuestionOfItsOwn((inU / slope).InnerSimplified, u, integrateByParts) is not { } answer)
return null;
var back = answer.Substitute(u, linear);
return back.Nodes.Any(node => node == MathS.NaN) ? null : back;
}

/// <summary>
/// Whether <paramref name="factor"/> is a power that is not whole of something holding a logarithm of something in
/// <paramref name="x"/>, or an exponential of something in <paramref name="x"/> that is not linear in it.
/// </summary>
private static bool IsATranscendentalPowerOfSomethingInX(Entity factor, Entity.Variable x) => factor switch
{
// An exponential whose exponent holds a sum in x, c (a + b x)^3 or c/(a + b x), read as not linear only then.
Powf(var @base, var exponent) when !@base.ContainsNode(x) && exponent.ContainsNode(x)
=> exponent.Nodes.Any(node => node is Sumf or Minusf && node.ContainsNode(x))
&& !TreeAnalyzer.TryGetPolyLinear(exponent, x, out _, out _),
Powf(var @base, var exponent) when !exponent.ContainsNode(x) && exponent is not Number.Integer
=> @base.Nodes.Any(node => node is Logf(_, var antilogarithm) && antilogarithm.ContainsNode(x)),
_ => false
};

/// <summary>
/// The one sum linear in <paramref name="x"/> that every <paramref name="x"/> in <paramref name="expr"/> stands in,
/// outermost, or <see langword="null"/>.
/// </summary>
private static Entity? TheOneLinearIn(Entity expr, Entity.Variable x)
{
Entity? found = null;
bool Read(Entity node)
{
if (!node.ContainsNode(x))
return true;
if (node is Sumf or Minusf && TreeAnalyzer.TryGetPolyLinear(node, x, out var slope, out _) && !slope.ContainsNode(x))
{
if (found is null)
found = node;
return node == found;
}
if (node == x)
return false;
return node.DirectChildren.All(Read);
}
return Read(expr) ? found : null;
}

/// <summary>
/// A sine or a cosecant of twice an argument beside functions of the argument, written as the
/// product it is: <c>sin(2A) = 2 sin(A) cos(A)</c>, so that every trigonometric function is of
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -935,6 +935,8 @@ internal static bool ASumOverRootsWouldAnswer
// A polynomial beside error functions of one shifted linear, written in it: by parts in
// x leaves a Gaussian of the shifted linear beside a polynomial, which nothing reads.
if ((answer = IndefiniteIntegralSolver.SolveAPolynomialBesideErrorFunctionsOfAShiftedLinear(expr, x, integrateByParts)) is { }) return answer;
// And beside a symbolic power of a logarithm of one, or an exponential of a power of one, the same way.
if ((answer = IndefiniteIntegralSolver.SolveAPolynomialBesideATranscendentalPowerOfAShiftedLinear(expr, x, integrateByParts)) is { }) return answer;
// A half-odd power of a ± a sin(y) beside powers of other linears in the sine, by the half
// angle, before the polynomial term: beneath it the substitution search ran out of time.
if ((answer = IndefiniteIntegralSolver.SolveAHalfOddPowerOfOnePlusMinusASineBesidePowersOfLinearsInIt(expr, x, integrateByParts)) is { }) return answer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ public void AHighWholePowerIsOneGammaFunction()
[InlineData("integral(e^(-x^3), x, 0, 1)", 0.807511182139671)]
// 3^(-2/3) on both half-lines, which is not a number but one constant.
[InlineData("integral(x^(1/3)*e^(-(1 + 3*x^2)), x, 0, 1)", 0.1169389395696306439)]
[InlineData("integral(x*(1/3 + 2*ln(3/2*(1 + 2*x)))^(5/2), x, 1, 2)", 47.01873105138465896167)]
public void ADefiniteIntegralFromZero(string integral, double value)
{
var result = integral.ToEntity().Simplify().EvalNumerical();
Expand Down Expand Up @@ -123,6 +124,18 @@ public void APositiveRateIsTakenOutOfThePower()
[InlineData("x^m*e^(-(a + b*x^2))")]
public void AHyperbolicFunctionOfAPowerOfX(string integrand) => DifferentiatesBack(integrand);

/// <summary>
/// A polynomial beside a symbolic power of a logarithm of one shifted linear, or an exponential of a power of one,
/// written in <c>u = a + b x</c>, where each term is a gamma function. The constant in front comes along. Rubi's 3.3,
/// 3.4 and 2.3.
/// </summary>
[Theory]
[InlineData("2*x*(a + b*ln(c*(d + f*x)))^n")]
[InlineData("x*(a + b*ln(c*(d + f*sqrt(x))))^n")]
[InlineData("x^2*f^(c*(a + b*x)^3)")]
[InlineData("(a + b*x)^2*e^(-c*(d + f*x)^3)")]
public void APolynomialBesideAFunctionOfAShiftedLinear(string integrand) => DifferentiatesBack(integrand);

/// <summary>
/// Not where the integral is elementary, an exponential integral or an error function: those keep the form
/// they had.
Expand Down
Loading