Skip to content

Commit 07f3e15

Browse files
Name a logarithm of nested powers of one linear as a multiple of the linear's logarithm (#2052)
Rubi's 3.3 (g + h x)^2 (a + b ln(c (d (e + f x)^p)^q))^3 was declined after eleven seconds and twelve gigabytes, where with ln(c (e + f x)^n) for the logarithm it is answered in a quarter of a second. The logarithm's derivative is p q f/(e + f x) by the chain rule on any branch, read off the nested powers as written, so it is p q ln(e + f x) + K with K constant wherever it is continuous, the generic case as SolveByNamingALogarithmLinearInTheVariable writes it. Named so, the integrand is a polynomial times a power of ln(e + f x), and the sum the name stands for is written back as the logarithm in the answer. Only a nested power, which the rules for ln(c L^n) do not read. Part of #233. Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent 1566841 commit 07f3e15

4 files changed

Lines changed: 138 additions & 0 deletions

File tree

‎BREAKING-CHANGES.md‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,22 @@ the working digits, or `MathS.Settings.PrecisionErrorZeroRange` where a caller h
565565
still that integer, so `e^(-123.456)` is 0 as it was.
566566
[#1338](https://github.com/asc-community/AngouriMath/issues/1338).
567567

568+
### A logarithm of nested powers of one linear is named as a multiple of the linear's logarithm
569+
570+
**Answers where there were none, and shorter ones.** Rubi's 3.3 `(g + h x)^2 (a + b ln(c (d (e + f x)^p)^q))^3` was declined
571+
after eleven seconds and twelve gigabytes. The logarithm's derivative is `p q f/(e + f x)` on any branch, so it is
572+
`p q ln(e + f x) + K`, with `K` constant wherever it is continuous. Named so, the integrand is a polynomial times a power
573+
of `ln(e + f x)`, and the answer writes the logarithm back as it was. The square and the cube beside a linear come out
574+
shorter. The first power beside a quadratic comes out a little longer
575+
([#718](https://github.com/asc-community/AngouriMath/issues/718)).
576+
577+
| Input | Was (2.5.0) | Now |
578+
|---|---|---|
579+
| `"(g+h*x)^2*(a+b*ln(c*(d*(k+f*x)^p)^q))^3".ToEntity().Integrate("x")` | `integral(...)` | 1,660 characters, where before this change master declined it after 11 s and 12 GB |
580+
| `"(g+h*x)^2*(a+b*ln(c*(d*(k+f*x)^p)^q))^2".ToEntity().Integrate("x")` | `integral(...)` | 1,051 characters, where before this change master gave 2,048 |
581+
| `"(g+h*x)*(a+b*ln(c*(d*(k+f*x)^p)^q))^3".ToEntity().Integrate("x")` | `integral(...)` | 702 characters, where before this change master gave 2,569 |
582+
| `"(g+h*x)^2*(a+b*ln(c*(d*(k+f*x)^p)^q))".ToEntity().Integrate("x")` | `integral(...)` | 631 characters, where before this change master gave 527 |
583+
568584
### A power of a power of a logarithm over x is integrated below the question asked too
569585

570586
**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

‎Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs‎

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30090,6 +30090,69 @@ Entity Named(Entity value)
3009030090
return Functions.PartialFractions.DerivativeHoldsAtSampledPoints(answer, expr, x) ? answer : null;
3009130091
}
3009230092

30093+
/// <summary>
30094+
/// A logarithm of constants and nested powers of one linear <c>L</c>, <c>ln(c (d L^p)^q)</c>, is
30095+
/// <c>p q ln(L) + K</c> with <c>K</c> constant wherever it is continuous, since its derivative is
30096+
/// <c>p q L'/L</c> by the chain rule on any branch: named so, Rubi's 3.3
30097+
/// <c>(g + h x)^2 (a + b ln(c (d (e + f x)^p)^q))^3</c> is a polynomial times a power of
30098+
/// <c>ln(e + f x)</c>, answered in a quarter of a second, where as written it was declined after
30099+
/// eleven and twelve gigabytes. The answer is the generic case's, as
30100+
/// <see cref="SolveByNamingALogarithmLinearInTheVariable"/>'s is. Only a nested power, which the
30101+
/// rules for <c>ln(c L^n)</c> do not read. Asked as a question of its own.
30102+
/// https://github.com/asc-community/AngouriMath/issues/718
30103+
/// </summary>
30104+
internal static Entity? SolveByNamingALogarithmOfNestedPowersOfALinear(Entity expr, Entity.Variable x, bool integrateByParts)
30105+
{
30106+
Logf? named = null;
30107+
Entity? linear = null;
30108+
Entity? times = null;
30109+
foreach (var node in expr.Nodes)
30110+
{
30111+
if (node is not Logf(var logBase, var argument) log || logBase != MathS.e || !argument.ContainsNode(x)
30112+
|| !argument.Nodes.Any(inner => inner is Powf(var raised, _) && raised.ContainsNode(x) && raised.Nodes.Any(deeper => deeper != raised && deeper is Powf(var b, _) && b.ContainsNode(x))))
30113+
continue;
30114+
Entity? found = null;
30115+
Entity? Exponent(Entity part)
30116+
{
30117+
if (!part.ContainsNode(x))
30118+
return Number.Integer.Zero;
30119+
if (TreeAnalyzer.TryGetPolyLinear(part, x, out var slope, out _) && !TreeAnalyzer.IsZero(slope))
30120+
{
30121+
if (found is null)
30122+
found = part;
30123+
return found == part ? Number.Integer.One : null;
30124+
}
30125+
switch (part)
30126+
{
30127+
case Mulf(var left, var right):
30128+
return Exponent(left) is { } l && Exponent(right) is { } r ? l + r : null;
30129+
case Divf(var above, var below):
30130+
return Exponent(above) is { } a && Exponent(below) is { } b ? a - b : null;
30131+
case Powf(var @base, var power) when !power.ContainsNode(x):
30132+
return Exponent(@base) is { } e ? power * e : null;
30133+
default:
30134+
return null;
30135+
}
30136+
}
30137+
if (Exponent(argument) is not { } exponent || found is null)
30138+
continue;
30139+
(named, linear, times) = (log, found, exponent.InnerSimplified);
30140+
break;
30141+
}
30142+
if (named is null || linear is null || times is null || TreeAnalyzer.IsZero(times))
30143+
return null;
30144+
var constant = Variable.CreateUnique(expr, "K");
30145+
var inTheLinear = times * MathS.Ln(linear) + constant;
30146+
var rewritten = expr.Substitute(named, inTheLinear);
30147+
if (rewritten == expr || rewritten.ContainsNode(named))
30148+
return null;
30149+
if (Integration.ComputeAsAQuestionOfItsOwn(rewritten, x, integrateByParts) is not { } answer)
30150+
return null;
30151+
// The sum as it was written stands for the logarithm again, where term by term it would be
30152+
// `p q ln(L) + (ln(c (d L^p)^q) - p q ln(L))`; K anywhere else is the difference.
30153+
return answer.Replace(node => node == inTheLinear ? named : node).Substitute(constant, named - times * MathS.Ln(linear));
30154+
}
30155+
3009330156
/// <summary>
3009430157
/// The sign of a real-valued function of <paramref name="x"/> among the factors of the
3009530158
/// integrand is constant on every interval between its zeros, and goes in front of the

‎Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,9 @@ internal static bool ASumOverRootsWouldAnswer
695695
// And a squared sine beside the squared cosine of its argument, the one they add up to:
696696
// `e^(cos(x)^2 + sin(x)^2)` was declined, written with an x its value does not hold.
697697
if ((answer = IndefiniteIntegralSolver.SolveByFoldingAPythagoreanPair(expr, x, integrateByParts)) is { }) return answer;
698+
// A logarithm of nested powers of one linear, `ln(c (d (e + f x)^p)^q)`, named as `p q ln(e + f x)`
699+
// plus a constant, before the rules that declined its cube beside a quadratic after twelve gigabytes.
700+
if ((answer = IndefiniteIntegralSolver.SolveByNamingALogarithmOfNestedPowersOfALinear(expr, x, integrateByParts)) is { }) return answer;
698701
// An arctangent over a power of d (1 +- i c x), under x = tan(u)/c, where 1 + i tan(u) is
699702
// e^(i u)/cos(u): the rules below ran out of time on `(a + b atan(c x))^2/(d + i c d x)^2`.
700703
if ((answer = IndefiniteIntegralSolver.SolveAnArctangentOverAPowerOfOnePlusICXUnderTheTangent(expr, x, integrateByParts)) is { }) return answer;
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//
2+
// Copyright (c) 2019-2026 Angouri.
3+
// AngouriMath is licensed under MIT.
4+
// Details: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.
5+
// Website: https://am.angouri.org.
6+
//
7+
8+
using System;
9+
using System.Threading;
10+
using System.Threading.Tasks;
11+
using AngouriMath.Extensions;
12+
using Xunit;
13+
14+
namespace AngouriMath.Tests.Calculus
15+
{
16+
/// <summary>
17+
/// A logarithm of nested powers of one linear, <c>ln(c (d (e + f x)^p)^q)</c>, named as
18+
/// <c>p q ln(e + f x) + K</c>, K constant where it is continuous: Rubi's 3.3
19+
/// <c>(g + h x)^2 (a + b ln(c (d (e + f x)^p)^q))^3</c> was declined after eleven seconds and twelve
20+
/// gigabytes, where in the linear's logarithm it is a polynomial times a power of it.
21+
/// <a href="https://github.com/asc-community/AngouriMath/issues/718">#718</a>
22+
/// </summary>
23+
[Trait("Area", "Calculus")]
24+
public sealed class ALogarithmOfNestedPowersOfALinearIntegralTest
25+
{
26+
[Theory]
27+
// Rubi 3.3:620, with k for Rubi's e.
28+
[InlineData("(g + h*x)^2*(a + b*ln(c*(d*(k + f*x)^p)^q))^3")]
29+
[InlineData("(g + h*x)*(a + b*ln(c*(d*(k + f*x)^p)^q))^3")]
30+
[InlineData("(g + h*x)^2*(a + b*ln(c*(d*(k + f*x)^p)^q))^2")]
31+
public void IsAnsweredWithTheLogarithmAsWritten(string integrand)
32+
{
33+
Entity? integral = null;
34+
// A thread of its own, so that the guard is not spent waiting behind other tests' work.
35+
var task = Task.Factory.StartNew(() => integral = integrand.ToEntity().Integrate("x"),
36+
CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
37+
Assert.True(task.Wait(LimitTermination.Guard), $"{integrand} did not finish within {LimitTermination.Guard}");
38+
var text = integral!.Stringize();
39+
Assert.DoesNotContain("integral(", text);
40+
Assert.Contains("ln(c * (d * (k + f * x) ^ p) ^ q)", text);
41+
Entity Pinned(Entity e) => e.Substitute("a", 1.3).Substitute("b", 0.7).Substitute("c", 0.4).Substitute("d", 0.9)
42+
.Substitute("f", 0.8).Substitute("g", 1.7).Substitute("h", 0.6).Substitute("k", 0.2).Substitute("p", 1.5).Substitute("q", 0.75);
43+
var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x");
44+
var original = Pinned(integrand.ToEntity());
45+
foreach (var at in new[] { 0.3, 0.9, 1.4, 2.1, 3.3 })
46+
{
47+
var want = original.Substitute("x", at).EvalNumerical();
48+
var got = derivative.Substitute("x", at).EvalNumerical();
49+
Assert.False(got.IsNaN, $"d/dx of the antiderivative of {integrand} has no value at x = {at}, where the integrand is {want}");
50+
Assert.True(Math.Abs((double)(got - want).RealPart) + Math.Abs((double)(got - want).ImaginaryPart)
51+
< 1e-9 * Math.Max(1, Math.Abs((double)want.RealPart) + Math.Abs((double)want.ImaginaryPart)),
52+
$"d/dx of the antiderivative of {integrand} is {got} at x = {at}, where the integrand is {want}");
53+
}
54+
}
55+
}
56+
}

0 commit comments

Comments
 (0)