Skip to content

Commit

Permalink
Remove warning from root finding (#32)
Browse files Browse the repository at this point in the history
* Remove warning from root finding

Return convergence status. Call one of two functions to error
on bad status or else ignore it.

* Remove warning diagnostic from lambertw

Replace `lambertw` with two functiions
* `lambertw`-- same as before, but silently returns a value with no warning if
   root finding fails to converge.
* `lambertw_check_convergence` -- same as `lambertw` if root finding converges. But
   throws an error if convergences fails. ie. `maxiter` is met.
  • Loading branch information
jlapeyre authored Oct 2, 2024
1 parent b82574a commit 6617072
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 8 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ also called the omega function or product logarithm.
```julia
lambertw(z,k) # Lambert W function for argument z and branch index k
lambertw(z) # the same as lambertw(z,0)
lambertw_check_convergence(z, k=0) # The same as above but throw an error if the computation failed to converge
```

`z` may be Complex or Real. `k` must be an integer. For Real
Expand All @@ -35,6 +36,11 @@ julia> lambertw(-pi/2 + 0im) / pi
4.6681174759251105e-18 + 0.5im
```

#### Note on `lambertw_check_convergence`

You can use this for extra safety. But I have been unable to find any input for which the root finding fails to
converge quickly.

### lambertwbp(x,k=0)

Return `1 + W(-1/e + z)`, for `z` satisfying `0 <= abs(z) < 1/e`,
Expand Down
34 changes: 26 additions & 8 deletions src/LambertW.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ module LambertW

import IrrationalConstants

export lambertw, lambertwbp
export lambertw, lambertwbp, lambertw_check_convergence

const omega_const_bf_ = Ref{BigFloat}()

Expand Down Expand Up @@ -52,9 +52,12 @@ If `z` is real, `k` must be either `0` or `-1`. For `Real` `z`, the domain of th
`k = -1` is `[-1/e, 0]` and the domain of the branch `k = 0` is `[-1/e, Inf]`. For
`Complex` `z`, and all `k`, the domain is the complex plane.
The result is computed via a root-finding loop. If the number of iterations is greater
than or equal to `maxits`, a warning is printed (or logged). In testing, this has never
been observed.
The result is computed via a root-finding loop. If the number of iterations exceeds
`maxits`, then the loop exits early, returning a result without warning about the failure
to converge. This will probably never happen. However, if you want to be more careful,
call `lambertw_check_convergence` instead. The latter function returns the result if
`maxits` was not reached, and otherwise throws an error.
```jldoctest
julia> lambertw(-1/MathConstants.e, -1)
-1.0
Expand All @@ -72,7 +75,23 @@ julia> lambertw(Complex(-10.0, 3.0), 4)
-0.9274337508660128 + 26.37693445371142im
```
"""
lambertw(z, k::Integer=0, maxits::Integer=1000) = _lambertw(float(z), k, maxits)
lambertw(z, k::Integer=0, maxits::Integer=1000) = _lambertw(float(z), k, maxits)[1]

"""
lambertw_check_convergence(z, k::Integer=0, maxits::Integer=1000)
This is the same as `lambertw` except that if the root finding fails to converge in `maxits` iterations,
an error is thrown.
"""
function lambertw_check_convergence(z, k::Integer=0, maxits::Integer=1000)
(w, converged) = _lambertw(float(z), k, maxits)
if ! converged
error("lambertw failed to converge in $maxits iterations")
end
w
end

#lambertw(z, k::Integer=0, maxits::Integer=1000) = _lambertw(float(z), k, maxits)

# lambertw(e + 0im, k) is ok for all k

Expand All @@ -88,7 +107,7 @@ end
# This appears to be inferrable with T=Float64 and T=BigFloat, including if x=Inf.
# There is a magic number here. It could be noted, or possibly removed.
# In particular, the fancy initial condition selection does not seem to help speed.
function lambertw_branch_zero(x::T, maxits)::T where T<:Real
function lambertw_branch_zero(x::T, maxits) where T<:Real
isnan(x) && return(NaN)
x == Inf && return Inf # appears to return convert(BigFloat, Inf) for x == BigFloat(Inf)
one_t = one(T)
Expand Down Expand Up @@ -172,8 +191,7 @@ function lambertw_root_finding(z::T, x0::T, maxits) where T <: Number
lastx = x
lastdiff = xdiff
end
converged || @warn("lambertw with z=", z, " did not converge in ", maxits, " iterations.")
return x
return (x, converged)
end

### Inverse of Lambert W function
Expand Down
4 changes: 4 additions & 0 deletions test/lambertw_test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,7 @@ end
@testset "show" begin
@test string(LambertW.Omega()) == "ω"
end

@testset "lambertw_check_convergence" begin
@test lambertw_check_convergence(1.0) == lambertw(1.0)
end

0 comments on commit 6617072

Please sign in to comment.