[R] Lambert's W function

Stefan Böhringer commercial at s-boehringer.de
Wed Nov 26 11:25:03 CET 2003


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




More information about the R-help mailing list