diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs index 942ebafc6..058e0c506 100644 --- a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs +++ b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs @@ -18222,8 +18222,9 @@ static EInteger Choose(int whole, int chosen) 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. + var (numerator, denominator) = expr is Divf(var above, var below) ? (above, below) : (expr, (Entity)Number.Integer.One); Entity? transcendental = null; - foreach (var factor in Mulf.LinearChildren(expr)) + foreach (var factor in Mulf.LinearChildren(numerator)) if (factor.ContainsNode(x) && IsATranscendentalPowerOfSomethingInX(factor, x)) { if (transcendental is not null) @@ -18233,7 +18234,7 @@ static EInteger Choose(int whole, int chosen) if (transcendental is null) return null; Entity? polynomial = null; - foreach (var factor in Mulf.LinearChildren(expr)) + foreach (var factor in Mulf.LinearChildren(numerator)) { if (!factor.ContainsNode(x) || ReferenceEquals(factor, transcendental)) continue; @@ -18247,6 +18248,18 @@ static EInteger Choose(int whole, int chosen) || !TreeAnalyzer.TryGetPolyLinear(linear, x, out var slope, out var offset) || slope.ContainsNode(x) || offset.ContainsNode(x) || TreeAnalyzer.IsZero(slope) || VanishesIdentically(offset)) return null; + // Below the bar, constants and whole powers of a multiple of the linear, which in u are powers of u: + // (h + j x)^2 (a + b ln(c (e + f x)))^p/(d e + d f x) is a polynomial in u over d u. + foreach (var factor in Mulf.LinearChildren(denominator)) + { + if (!factor.ContainsNode(x)) + continue; + var linearBelow = factor is Powf(var powered, Number.Integer { EInteger.Sign: > 0 }) ? powered : factor; + if (!TreeAnalyzer.TryGetPolyLinear(linearBelow, x, out var belowSlope, out var belowOffset) + || belowSlope.ContainsNode(x) || belowOffset.ContainsNode(x) + || !VanishesIdentically(belowSlope * offset - belowOffset * slope)) + 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)) diff --git a/Sources/Tests/UnitTests/Calculus/APowerBesideAnExponentialOfAPowerIntegralTest.cs b/Sources/Tests/UnitTests/Calculus/APowerBesideAnExponentialOfAPowerIntegralTest.cs index fb101a74d..ddc8d77bc 100644 --- a/Sources/Tests/UnitTests/Calculus/APowerBesideAnExponentialOfAPowerIntegralTest.cs +++ b/Sources/Tests/UnitTests/Calculus/APowerBesideAnExponentialOfAPowerIntegralTest.cs @@ -126,9 +126,9 @@ public void APositiveRateIsTakenOutOfThePower() /// /// A polynomial beside a symbolic power of a logarithm of one shifted linear, or an exponential of a power of one, - /// written in u = a + b x, where each term is a gamma function. The constant in front comes along. And beside - /// a sine or a cosine of a power of one, which in u is Euler's formula's exponentials of a power of u. Rubi's 3.3, - /// 3.4, 2.3 and 4.1.12. + /// written in u = a + b x, where each term is a gamma function. The constant in front comes along, and a power + /// of a multiple of the linear below the bar, which in u is a power of u. And beside a sine or a cosine of a power of + /// one, which in u is Euler's formula's exponentials of a power of u. Rubi's 3.3, 3.4, 2.3 and 4.1.12. /// [Theory] [InlineData("2*x*(a + b*ln(c*(d + f*x)))^n")] @@ -139,6 +139,8 @@ public void APositiveRateIsTakenOutOfThePower() [InlineData("x*sin(a + b*(c + d*x)^n)")] [InlineData("x^2*cos(a + b/(c + d*x)^3)")] [InlineData("x*(a + b*sin(c + d*(f + x)^n))^2")] + [InlineData("(a + b*x)^2*(f + ln(c + d*x))^n/(a*c + a*d*x)")] + [InlineData("x*(f + ln(c*(c + d*x)))^n/(c + d*x)^2")] public void APolynomialBesideAFunctionOfAShiftedLinear(string integrand) => DifferentiatesBack(integrand); ///