From 9c4a70482241b23f1d7777155e9800acc2c2fbf4 Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Wed, 21 Oct 2026 21:47:41 +0000 Subject: [PATCH] Integrate a power of a power of a logarithm over x below the question asked SolvePowersOfOneLinearAsOnePower answered only at the question asked. Under u = ln(a x^n), Rubi's 3.5 (ln(a x^n)^2)^p/x is (u^2)^p/n, a symbolic power of a power of the variable, and that is a question below the top. Below it the rule now reads powers of the variable itself, with no sum in x in them, and (u^2)^p is u (u^2)^p/(2 p + 1) on both sides of u = 0. Chain against master 2a98be40: pocket 5661 -> 5662 solved of 5675, 0 wrong; every family's samples unchanged; the one row that moved, 3.5:188, master declines and this answers. 11,193 rows compared for allocation, none grew past 1.3x and 300 MB. Part of #233. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura --- BREAKING-CHANGES.md | 14 ++++++ .../Integration/IndefiniteIntegralSolver.cs | 5 +- ...werOfASquaredLogarithmOverXIntegralTest.cs | 50 +++++++++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 Sources/Tests/UnitTests/Calculus/APowerOfASquaredLogarithmOverXIntegralTest.cs diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md index 7b8cb4a18..398929806 100644 --- a/BREAKING-CHANGES.md +++ b/BREAKING-CHANGES.md @@ -398,6 +398,20 @@ the working digits, or `MathS.Settings.PrecisionErrorZeroRange` where a caller h still that integer, so `e^(-123.456)` is 0 as it was. [#1338](https://github.com/asc-community/AngouriMath/issues/1338). +### A power of a power of a logarithm over x is integrated below the question asked too + +**Answers where there were none.** Rubi's 3.5 `(ln(a x^n)^2)^p/x` was declined. Under `u = ln(a x^n)` it is +`(u^2)^p/n`, a symbolic power of a power of the variable, and the rule for powers of one linear answered that only +where it was the question asked; below it, the rule now reads powers of the variable itself, with no sum in it. Its integral is +`u (u^2)^p/(2 p + 1)` on both sides of `u = 0`, written as `(u^2)^p/u^(2 p)`, constant on each side, times +`u^(2 p + 1)/(2 p + 1)` ([#233](https://github.com/asc-community/AngouriMath/issues/233)). + +| Input | Was (2.5.0) | Now | +|---|---|---| +| `"(ln(x)^2)^p/x".ToEntity().Integrate("x")` | `integral(...)` | 79 characters | +| `"(ln(a*x^n)^2)^p/x".ToEntity().Integrate("x")` | `integral(...)` | 107 characters | +| `"(ln(a*x)^3)^p/x".ToEntity().Integrate("x")` | `integral(...)` | 91 characters | + ### A polynomial over a power of the linear of an artanh is written in powers of the linear **Answers where there were none.** `x (a + b atanh(c x))^2/(d + c d x)^3`, Rubi's 7.3.4, ran out of time. In powers of diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs index 5a953b156..67b81618e 100644 --- a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs +++ b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs @@ -26501,7 +26501,10 @@ Entity ToThe(EInteger k) /// internal static Entity? SolvePowersOfOneLinearAsOnePower(Entity expr, Entity.Variable x, bool integrateByParts) { - if (!Integration.AnsweringTheQuestionAsked) + // Below the top only powers of x itself, with no sum in x to read: `(u^2)^p`, which + // `u = ln(x)` makes of Rubi's 3.5 `(ln(x)^2)^p/x`, is `u (u^2)^p/(2 p + 1)` and was + // declined there. + if (!Integration.AnsweringTheQuestionAsked && expr.Nodes.Any(node => node is Sumf or Minusf && node.ContainsNode(x))) return null; // Without a leading `1 *`, which is another spelling to the rules that read the result. static Entity Times(Entity a, Entity b) => a == Number.Integer.One ? b : a * b; diff --git a/Sources/Tests/UnitTests/Calculus/APowerOfASquaredLogarithmOverXIntegralTest.cs b/Sources/Tests/UnitTests/Calculus/APowerOfASquaredLogarithmOverXIntegralTest.cs new file mode 100644 index 000000000..e741bd3d1 --- /dev/null +++ b/Sources/Tests/UnitTests/Calculus/APowerOfASquaredLogarithmOverXIntegralTest.cs @@ -0,0 +1,50 @@ +// +// 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 +{ + /// + /// A symbolic power of a power of the variable, asked below the question: u = ln(x) makes + /// Rubi's 3.5 (ln(x)^2)^p/x the question (u^2)^p, which is u (u^2)^p/(2 p + 1) + /// on every branch and was answered only where it was the question asked. + /// #233 + /// + [Trait("Area", "Calculus")] + public sealed class APowerOfASquaredLogarithmOverXIntegralTest + { + [Theory] + [InlineData("(ln(x)^2)^p/x")] + [InlineData("(ln(a*x^n)^2)^p/x")] + [InlineData("(ln(a*x)^3)^p/x")] + public void DifferentiatesBack(string integrand) + { + var integral = integrand.ToEntity().Integrate("x"); + Assert.DoesNotContain("integral(", integral.Stringize()); + Entity Pinned(Entity e) => e.Substitute("a", 1.3).Substitute("n", 2.0).Substitute("p", 0.35); + var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x"); + var original = Pinned(integrand.ToEntity()); + var compared = 0; + // Both sides of ln = 0, where (ln^2)^p is real and ln^(2p) is not. + foreach (var at in new[] { 0.2, 0.5, 0.8, 1.4, 2.6, 4.1 }) + { + var want = original.Substitute("x", at).EvalNumerical(); + var got = derivative.Substitute("x", at).EvalNumerical(); + if (want.IsNaN || got.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}"); + } + } +}