From c5dc498460dce95d0165a25ab5e53bd7681e5ac7 Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Fri, 23 Oct 2026 11:13:57 +0000 Subject: [PATCH] Integrate a power of a logarithm beside a linear in another as two powers of the first (a + b L)^p (d + e M), with L = ln(c x^n) and M = ln(f x^r), was declined, and so was it with M = L. M is (r/n) L + delta, where delta = M - (r/n) L is constant between the cuts: its derivative is r/x - (r/n)(n/x) = 0. So d + e M is alpha (a + b L) + beta with alpha = e r/(n b), and the integrand is alpha (a + b L)^(p + 1) + beta (a + b L)^p beside what else is there, each answered by the rules for a power of one logarithm. delta is written back in the answer. Asked after the product of powers read as a derivative, which writes p x^m ln(x)^n ((m + 1) ln(x) + n + 1) as p x^(m + 1) ln(x)^(n + 1), where this would write a sum of gamma functions. Part of #2075. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura --- .../Integration/IndefiniteIntegralSolver.cs | 69 +++++++++++++++++++ .../Integration/Integration.Definition.cs | 4 ++ ...BesideAnExponentialOfAPowerIntegralTest.cs | 11 +++ 3 files changed, 84 insertions(+) diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs index de6928d45..a5cfa4a96 100644 --- a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs +++ b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs @@ -18314,6 +18314,75 @@ private static (Entity Binomial, Entity Offset, Entity Scale, Entity Exponent)? return exponent is null ? null : (sum, offset, scale, exponent.InnerSimplified); } + /// + /// A power that is not whole of a linear in one logarithm L = ln(c x^n), beside a linear in it or in another + /// logarithm of a power of x, (a + b L)^p (d + e M) with M = ln(f x^r). M is (r/n) L + delta, + /// where delta = M - (r/n) L is constant between the cuts, its derivative being r/x - (r/n)(n/x) = 0. + /// So d + e M is alpha (a + b L) + beta, with alpha = e r/(n b) and + /// beta = d + e delta - alpha a, and the integrand is alpha (a + b L)^(p + 1) + beta (a + b L)^p beside + /// what else is there: powers of the one logarithm, which the rules for those answer. delta is written back in the + /// answer. Rubi's 3.1.5. https://github.com/asc-community/AngouriMath/issues/2075 + /// + internal static Entity? SolveAPowerOfALogarithmBesideALinearInALogarithm(Entity expr, Entity.Variable x, bool integrateByParts) + { + if (!Integration.AnsweringTheQuestionAskedOrOneBelow || expr is not (Mulf or Divf)) + return null; + var (numerator, denominator) = expr is Divf(var above, var below) ? (above, below) : (expr, (Entity)Number.Integer.One); + Powf? power = null; + Entity? linear = null; + Entity beside = Number.Integer.One; + foreach (var factor in Mulf.LinearChildren(numerator)) + { + if (power is null && factor is Powf(var @base, var exponent) candidate && exponent is not Number.Integer + && !exponent.ContainsNode(x) && TheLinearInOneLogarithm(@base, x) is not null) + power = candidate; + else if (linear is null && factor.ContainsNode(x) && factor is Logf or Sumf or Minusf && TheLinearInOneLogarithm(factor, x) is not null) + linear = factor; + else + beside *= factor; + } + if (power is null || linear is null + || TheLinearInOneLogarithm(power.Base, x) is not var (logarithm, degree, a, b) + || TheLinearInOneLogarithm(linear, x) is not var (other, otherDegree, d, e)) + return null; + var ratio = (otherDegree / degree).InnerSimplified; + Entity delta = other == logarithm ? Number.Integer.Zero : Variable.CreateUnique(expr, "delta_log"); + var alpha = e * ratio / b; + var beta = d + e * delta - alpha * a; + beside /= denominator; + if (Integration.ComputeAsAQuestionOfItsOwn((beside * MathS.Pow(power.Base, power.Exponent + 1)).InnerSimplified, x, integrateByParts) is not { } raised + || Integration.ComputeAsAQuestionOfItsOwn((beside * power).InnerSimplified, x, integrateByParts) is not { } asWritten) + return null; + var answer = alpha * raised + beta * asWritten; + if (delta is Variable constant) + answer = answer.Substitute(constant, other - ratio * logarithm); + return answer.Nodes.Any(node => node == MathS.NaN) ? null : answer; + } + + /// + /// as a + b L, linear in one logarithm L = ln(c x^n) and free of x otherwise, + /// with the logarithm, n, a and b; or . + /// + private static (Entity Logarithm, Entity Degree, Entity Offset, Entity Slope)? TheLinearInOneLogarithm(Entity expr, Entity.Variable x) + { + Entity? logarithm = null; + foreach (var node in expr.Nodes) + if (node is Logf(var @base, var antilogarithm) && @base == MathS.e && antilogarithm.ContainsNode(x)) + { + if (logarithm is not null && node != logarithm) + return null; + logarithm = node; + } + if (logarithm is not Logf(_, var argument) || TheMonomial(argument, x) is not var (_, degree) || TreeAnalyzer.IsZero(degree)) + return null; + var l = Variable.CreateUnique(expr, "l_log"); + var inL = expr.Replace(node => node == logarithm ? l : node); + if (inL.ContainsNode(x) || !TreeAnalyzer.TryGetPolyLinear(inL, l, out var slope, out var offset) + || slope.ContainsNode(l) || offset.ContainsNode(l) || TreeAnalyzer.IsZero(slope)) + return null; + return (logarithm, degree, offset, slope); + } + /// /// Whether is a power that is not whole of something holding a logarithm of something in /// , or an exponential of something in that is not linear in it. diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs b/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs index 8c5187315..e88ea959a 100644 --- a/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs +++ b/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs @@ -1838,6 +1838,10 @@ internal static bool ASumOverRootsWouldAnswer // And a product of powers that is the derivative of one with symbolic exponents, its // constant read at a point where the quotient of the brackets does not simplify free of x. if ((answer = IndefiniteIntegralSolver.SolveAsTheDerivativeOfAProductOfPowersReadAtAPoint(expr, x, integrateByParts)) is { }) return answer; + // A power of a logarithm beside a linear in another as two powers of the first, after the product of powers read + // as a derivative: p x^m ln(x)^n ((m + 1) ln(x) + n + 1) is p x^(m + 1) ln(x)^(n + 1) there, and a sum of gamma + // functions here. https://github.com/asc-community/AngouriMath/issues/2075 + if ((answer = IndefiniteIntegralSolver.SolveAPowerOfALogarithmBesideALinearInALogarithm(expr, x, integrateByParts)) is { }) return answer; // An arcoth of a linear as its artanh plus a constant, last of all, so that every arcoth // answered as written keeps that answer: `acoth(x)^2/(1 - x^2)^2` is // `(atanh(x) + K)^2/(1 - x^2)^2` with `K = acoth(x) - atanh(x)`, constant where it is diff --git a/Sources/Tests/UnitTests/Calculus/APowerBesideAnExponentialOfAPowerIntegralTest.cs b/Sources/Tests/UnitTests/Calculus/APowerBesideAnExponentialOfAPowerIntegralTest.cs index 35f7d0ee6..4d2473448 100644 --- a/Sources/Tests/UnitTests/Calculus/APowerBesideAnExponentialOfAPowerIntegralTest.cs +++ b/Sources/Tests/UnitTests/Calculus/APowerBesideAnExponentialOfAPowerIntegralTest.cs @@ -157,6 +157,17 @@ public void APositiveRateIsTakenOutOfThePower() [InlineData("(a - b*ln(c*(d + f/x^(1/3))^2))^n/x^2")] public void APowerOfXBesideAFunctionOfABinomial(string integrand) => DifferentiatesBack(integrand); + /// + /// A power of a linear in one logarithm of a power of x beside a linear in it or in another, which is the first + /// times a ratio of degrees plus a constant between the cuts: two powers of the one logarithm. Rubi's 3.1.5. + /// + [Theory] + [InlineData("(f - b*ln(c*x^2))^n*(d + a*ln(f*x^3))")] + [InlineData("x^2*(f - b*ln(c*x))^n*(d + a*ln(f*x^3))")] + [InlineData("(f - b*ln(c*x))^n*(d + a*ln(c*x))/x^2")] + [InlineData("(d*x)^m*(f - b*ln(c*x^2))^n*ln(a*x)")] + public void APowerOfALogarithmBesideALinearInALogarithm(string integrand) => DifferentiatesBack(integrand); + /// /// Not where the integral is elementary, an exponential integral or an error function: those keep the form /// they had.