From 19000a333a8249e86cca95fb3930c5f39a257445 Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Fri, 30 Oct 2026 18:13:07 +0000 Subject: [PATCH] LambertW over the reals is defined where its branch is real lambertw's condition was the complex one under either reading: every whole branch, and every z but 0 off the principal one. So DomainConditionIn(Domain.Real) of lambertw(0, x) was True, though W_0(-1) is -0.318 + 1.337i. Over the reals the condition is now where the branch is real: W_0 for z >= -1/e, W_(-1) for -1/e <= z < 0, both -1 at -1/e, and no other branch anywhere. The complex condition is unchanged. LambertWOverTheRealsTest takes three branches at twelve real points over the reals, and three over the complex numbers; five fail on master. lambertw is new since 2.6.0, so no answer changes against it. Found by work/domaincheck. Part of #2256. Co-Authored-By: Claude Opus 5.5 (1M context) --- Sources/.editorconfig | 3 ++ ...aluation.Continuous.Arithmetics.Classes.cs | 8 ++- .../Convenience/LambertWOverTheRealsTest.cs | 54 +++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 Sources/Tests/UnitTests/Convenience/LambertWOverTheRealsTest.cs diff --git a/Sources/.editorconfig b/Sources/.editorconfig index 0033226ad..29c5a0517 100644 --- a/Sources/.editorconfig +++ b/Sources/.editorconfig @@ -255,6 +255,9 @@ file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed [Tests/UnitTests/Convenience/MatrixFunctionsInAnExpressionTest.cs] file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed under MIT.\nDetails: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.\nWebsite: https://am.angouri.org.\n +[Tests/UnitTests/Convenience/LambertWOverTheRealsTest.cs] +file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed under MIT.\nDetails: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.\nWebsite: https://am.angouri.org.\n + [Tests/UnitTests/Common/ExponentialOfALogarithmTest.cs] file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed under MIT.\nDetails: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.\nWebsite: https://am.angouri.org.\n diff --git a/Sources/AngouriMath/Functions/Evaluation/Evaluation.Continuous/Evaluation.Continuous.Arithmetics.Classes.cs b/Sources/AngouriMath/Functions/Evaluation/Evaluation.Continuous/Evaluation.Continuous.Arithmetics.Classes.cs index f8a8bc6fd..e57ce443d 100644 --- a/Sources/AngouriMath/Functions/Evaluation/Evaluation.Continuous/Evaluation.Continuous.Arithmetics.Classes.cs +++ b/Sources/AngouriMath/Functions/Evaluation/Evaluation.Continuous/Evaluation.Continuous.Arithmetics.Classes.cs @@ -753,8 +753,14 @@ private static Entity Numerically(Complex n, int m) public partial record LambertWf { // Every whole branch, and every z but 0 off the principal branch, where W_k(z) goes to -oo as ln z does. + // Over the reals, where a branch is real: W_0 for z >= -1/e and W_(-1) for -1/e <= z < 0, both -1 at + // -1/e; no other branch is real anywhere. The condition was the complex one under either reading, so it + // held for W_0(-1), which is -0.318 + 1.337i. https://github.com/asc-community/AngouriMath/issues/2256 private protected override Entity IntrinsicCondition => - Branch.In(MathS.Sets.Z) & (Branch.Equalizes(Integer.Zero) | !Argument.Equalizes(Integer.Zero)); + Codomain < Domain.Complex + ? Branch.Equalizes(Integer.Zero) & Argument >= -1 / MathS.e + | Branch.Equalizes(Integer.Create(-1)) & Argument >= -1 / MathS.e & Argument < 0 + : Branch.In(MathS.Sets.Z) & (Branch.Equalizes(Integer.Zero) | !Argument.Equalizes(Integer.Zero)); /// protected override Entity InnerSimplify(bool isExact) => diff --git a/Sources/Tests/UnitTests/Convenience/LambertWOverTheRealsTest.cs b/Sources/Tests/UnitTests/Convenience/LambertWOverTheRealsTest.cs new file mode 100644 index 000000000..2e3c9b7fa --- /dev/null +++ b/Sources/Tests/UnitTests/Convenience/LambertWOverTheRealsTest.cs @@ -0,0 +1,54 @@ +// +// 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 AngouriMath; +using AngouriMath.Core; +using AngouriMath.Extensions; +using Xunit; + +namespace AngouriMath.Tests.Convenience +{ + /// + /// Over the reals the Lambert W function is defined where its branch is real: W_0 for z >= -1/e and + /// W_(-1) for -1/e <= z < 0. The condition was the complex one under either reading, so it held for + /// W_0(-1), which is -0.318 + 1.337i. + /// #2256 + /// + [Trait("Area", "Convenience")] + public sealed class LambertWOverTheRealsTest + { + [Theory] + [InlineData("lambertw(0, x)", "-3", false)] + [InlineData("lambertw(0, x)", "-1", false)] + [InlineData("lambertw(0, x)", "-1/e", true)] + [InlineData("lambertw(0, x)", "-1/5", true)] + [InlineData("lambertw(0, x)", "0", true)] + [InlineData("lambertw(0, x)", "2", true)] + [InlineData("lambertw(-1, x)", "-1/e", true)] + [InlineData("lambertw(-1, x)", "-1/5", true)] + [InlineData("lambertw(-1, x)", "-1/2", false)] + [InlineData("lambertw(-1, x)", "0", false)] + [InlineData("lambertw(-1, x)", "1", false)] + [InlineData("lambertw(1, x)", "1", false)] + public void OverTheRealsItIsWhereItsBranchIsReal(string expression, string at, bool defined) + { + var condition = expression.ToEntity().DomainConditionIn(Domain.Real).Substitute("x", at.ToEntity()).Evaled; + Assert.Equal(defined ? Entity.Boolean.True : Entity.Boolean.False, condition); + } + + /// Over the complex numbers every branch is defined but off the principal one at 0. + [Theory] + [InlineData("lambertw(0, x)", "-3", true)] + [InlineData("lambertw(-1, x)", "1", true)] + [InlineData("lambertw(-1, x)", "0", false)] + public void OverTheComplexNumbersItIsAsItWas(string expression, string at, bool defined) + { + var condition = expression.ToEntity().DomainCondition.Substitute("x", at.ToEntity()).Evaled; + Assert.Equal(defined ? Entity.Boolean.True : Entity.Boolean.False, condition); + } + } +}