On Tue, 2003-11-25 at 12:09, Robin Hankin wrote:
> Hello List
> 
> does anyone have an R function for the Lambert W function?  I need 
> complex arguments.
> 
> [the Lamert W function W(z) satisfies
> 
> W(z)*exp(W(z)) = z
> 
> but I could'nt even figure out how to use uniroot() for complex z]
> 
> 

There are several 'branches' of W(z) for complex arguments, since the
inverse of f(z) = z * exp(z) does not exist. Therefore you have to
constrain root-finding methods appropriately.

Here is an implementation for real valued arguments, if that is of any
help to you:

WE1 <- function(x) {
        if (1) {
        o <- optim(c(1),
                # optimize squared difference of z and log(t) + t
                function(t) { (x - (log(t[1]) + t[1]))**2 },
                # the gradient of the above function
                #function(t) { 2(log(t[1]) + t[1] - x)(1/t[1] - 1) },
                method="L-BFGS-B", lower=exp(-70),
                        control = list(lmm=40, maxit=10000, factr=1e9));
        } else {
        o <- optim(c(1),
                # optimize squared difference of z and log(t) + t
                function(t) { (x - (log(t[1]) + t[1]))**2 },
                method="BFGS");
        }
        o$par
}

W2 <- function(x) {
        eps <- 10^-5;   # precision

        if (x == 0) {
                wnew <- 0
        } else {
                # initial guess
                wold <- if (x < 2.5) {
                        (x + 4/3*x^2)/(1 + 7/3*x + 5/6*x^2)
                } else {
                        log(x)
                };
                if (x < 0) print("error");
                        lx <- log(x);
                wnew <- 2 * wold;
                if (x != Inf) {
                        while (abs( (wnew - wold)/wold ) > eps) {
                                wold <- wnew
                                zn <- lx - wold - log(wold);
                                y <- 2*(1 + wold)*((1 + wold) + 2/3*zn) - zn;
                                wnew <- wold*(1 + (zn * y)/((1 + wold)*(y - zn)));
                        }
                } else {
                        wnew <- Inf;
                }
        }
        wnew
}
WE <- function(z) {
        if ( z < -1 ) { W2(exp(z)) }
        else { WE1(z) };
}
W <- function(z) { WE(log(z)) }


Stefan

______________________________________________
[EMAIL PROTECTED] mailing list
https://www.stat.math.ethz.ch/mailman/listinfo/r-help

Reply via email to