From e170ed6cd7ba305dd14222ede80c3cf985038d0f Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Tue, 3 Nov 2026 18:07:55 +0000 Subject: [PATCH] Ask a quotient of logarithms' derivatives as one quotient Where both logarithms of a quotient diverge, SolveAsLogarithmDivision takes the limit of the ratio of their logarithmic derivatives, and asked it as a quotient of quotients, (u'/u) / (v'/v). For ln(x - 1) / ln(ln(x)) at 1 that is (1/(x - 1)) / ((1/x) / ln(x)), and its limit took 8.7 s, where x ln(x) / (x - 1), the same function, takes 26 ms. The limit at 1 took 11.9 s from the left, 6 s from the right and 16 s two-sided. The left side took 14 ms before #2275, which rightly sent it to this rule; the right was already 5.5 s in 2.6.0. limitcheck, which gives each limit five seconds, found it on SEED=16. The ratio is asked as u' v / (u v'). The limit at 1 is 1 from each side, as before, in 191 ms, 40 ms and 59 ms. limitcheck on seeds 14 to 16 finds no limit of another value and no new NaN, and the two that did not finish now agree with the values. Co-Authored-By: Claude Opus 5.5 --- .../Limits/Solvers/Limit.Solvers.cs | 9 +++-- ...entOfLogarithmsIsAskedAsOneQuotientTest.cs | 39 +++++++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 Sources/Tests/UnitTests/Calculus/AQuotientOfLogarithmsIsAskedAsOneQuotientTest.cs diff --git a/Sources/AngouriMath/Functions/Continuous/Limits/Solvers/Limit.Solvers.cs b/Sources/AngouriMath/Functions/Continuous/Limits/Solvers/Limit.Solvers.cs index de80ceff4..d31fc920d 100644 --- a/Sources/AngouriMath/Functions/Continuous/Limits/Solvers/Limit.Solvers.cs +++ b/Sources/AngouriMath/Functions/Continuous/Limits/Solvers/Limit.Solvers.cs @@ -331,9 +331,12 @@ private static bool LogarithmDiverges(Entity argumentLimit) if (upperDerivative.Nodes.Any(node => node is Derivativef) || lowerDerivative.Nodes.Any(node => node is Derivativef)) return null; - var p = (upperDerivative / upperLogArgument).InnerSimplified; - var q = (lowerDerivative / lowerLogArgument).InnerSimplified; - return LimitFunctional.ComputeLimit(p / q, x, Real.PositiveInfinity); + // (u'/u) / (v'/v) asked as the one quotient u' v / (u v'): asked as a quotient of + // quotients, the limit of ln(x - 1) / ln(ln(x)) at 1 from the left took twelve + // seconds over (1/(x - 1)) / ((1/x) / ln(x)), where x ln(x) / (x - 1) takes a + // hundredth of one. It took 14 ms before #2275 sent it to this rule. + var ratio = (upperDerivative * lowerLogArgument / (upperLogArgument * lowerDerivative)).InnerSimplified; + return LimitFunctional.ComputeLimit(ratio, x, Real.PositiveInfinity); } else diff --git a/Sources/Tests/UnitTests/Calculus/AQuotientOfLogarithmsIsAskedAsOneQuotientTest.cs b/Sources/Tests/UnitTests/Calculus/AQuotientOfLogarithmsIsAskedAsOneQuotientTest.cs new file mode 100644 index 000000000..54824897c --- /dev/null +++ b/Sources/Tests/UnitTests/Calculus/AQuotientOfLogarithmsIsAskedAsOneQuotientTest.cs @@ -0,0 +1,39 @@ +// +// 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 System.Threading.Tasks; +using AngouriMath.Core; +using Xunit; +using static AngouriMath.Entity; + +namespace AngouriMath.Tests.Calculus +{ + /// + /// A quotient of two logarithms that both diverge is the limit of the quotient of their logarithmic derivatives, + /// and that was asked as a quotient of quotients, (u'/u) / (v'/v). For ln(x - 1) / ln(ln(x)) at 1 that + /// is (1/(x - 1)) / ((1/x) / ln(x)), whose limit took twelve seconds from the left and six from the right, + /// where x ln(x) / (x - 1), the same function, takes a fraction of one. Found by limitcheck, which gave each + /// side five seconds; no issue was filed. The cap here is far from both: the fixed limit takes about 0.2 s. + /// + [Trait("Area", "Calculus")] + public sealed class AQuotientOfLogarithmsIsAskedAsOneQuotientTest + { + [Theory] + [InlineData("ln(x - 1) / ln(ln(x))", ApproachFrom.Left)] + [InlineData("ln(x - 1) / ln(ln(x))", ApproachFrom.Right)] + [InlineData("ln(x - 1) / ln(ln(x))", ApproachFrom.BothSides)] + [InlineData("log(ln(x), x - 1)", ApproachFrom.Left)] + [InlineData("ln(1 - x) / ln(-ln(x))", ApproachFrom.Left)] + public void IsOneAtOne(string input, ApproachFrom side) + { + var task = Task.Factory.StartNew(() => MathS.FromString(input).Limit("x", 1, side), TaskCreationOptions.LongRunning); + Assert.True(task.Wait(TimeSpan.FromSeconds(4)), $"the limit of {input} at 1, {side}, did not finish in four seconds"); + Assert.Equal(Number.Integer.One, task.Result); + } + } +}