Estoy buscando una aproximación simple, económica y muy precisa de la función de Lambert (W0 rama) (−1/e<x<0).
Respuestas
¿Demasiados anuncios?Aquí hay un post que hice en el sci.matemáticas hace un tiempo, con respecto a un método que yo he utilizado.
Análisis de wew
Para w>0, wew aumenta monótonamente de 0 a ∞. Cuando w<0, wew es negativo.
Por lo tanto, para x>0, W(x) es positivo y bien definido y aumenta monótonamente.
Para w<0, wew llega a un mínimo de −1/e a w=−1. En (−1,0), wew aumenta monótonamente de −1/e a 0. En (−∞,−1), wew disminuye monótona de 0 a −1/e. Por lo tanto, en (−1/e,0), W(x) puede tener uno de dos valores, uno en (−1,0) y otro en (−∞,−1). El valor en (−1,0) es llamado el principal valor.
La iteración
Utilizando el método de Newton para resolver wew produce el siguiente proceso iterativo paso para encontrar W(x): wnuevo=xew+w2w+1
Los valores iniciales de w
Para el principal valor, al −1/e≤x<0, y al 0≤x≤10, el uso de w=0. Al x>10, el uso de w=log(x)−log(log(x)).
Para el no-valor principal, al x es de [−1/e,−.1], el uso de w=−2; y si x es de (−.1,0), el uso de w=log(−x)−log(−log(−x)).
Esto nos dice que para la rama que desea, utilice la iteración con un valor inicial de w=0.
Corless, et al. De 1996, es una buena referencia para la aplicación de los Lambert W. Una de las claves para ser eficiente es una buena estimación inicial para el refinamiento iterativo. Aquí es donde la serie de aproximaciones son útiles. Para (−1/e,0) es muy útil el uso de dos diferentes expansiones: acerca de 0 y sobre el punto de ramificación de la −1/e. De lo contrario, se podrían perder un montón de tiempo de ejecución de las iteraciones.
He aquí algunos unvectorized (para mayor claridad) código de Matlab para W0. He indicado la ecuación números de Corless, et al. en el que varias líneas de base.
function w = fastW0(x)
% Lambert W function, upper branch, W_0
% Only valid for real-valued scalar x in [-1/e, 0]
if x > -exp(-sqrt(2))
% Series about 0, Eq. 3.1
w = ((((125*x-64)*x+36)*x/24-1)*x+1)*x;
else
% Series about branch point, -1/e, Eq. 4.22
p = sqrt(2*(exp(1)*x+1));
w = p*(1-(1/3)*p*(1-(11/24)*p*(1-(86/165)*p*(1-(769/1376)*p))))-1;
end
tol = eps(class(x));
maxiter = 4;
for i = 1:maxiter
ew = exp(w);
we = w*ew;
r = we-x; % Residual, Eq. 5.2
if abs(r) < tol
return;
end
% Halley's method, for Lambert W from Corless, et al. 1996, Eq. 5.9
w = w-r/(we+ew-0.5*r*(w+2)/(w+1));
end
Aquí está una parcela de doble precisión, tolerancia a la máquina epsilon) de número de iteraciones hasta que la convergencia si no se utiliza ningún inicial de la serie, supongo, la serie acerca de la 0, la serie sobre el punto de rama, o de ambas series:
Por supuesto, la evaluación de las series de aproximación tiene un costo en relación a la realización de una iteración. Uno puede ajustar el número de términos que se utilizan con el fin de sintonizar este.
Un procedimiento iterativo, dado en wikipedia, q & d-traducido a Pari / GP, que se adapta bien a mis necesidades:
LW(x, prec=1E-80, maxiters=200) = local(w, we, w1e);
w=0;
for(i=1,maxiters,
we=w*exp(w);
w1e=(w+1)*exp(w);
if(prec>abs((x-we)/w1e),return(w));
w = w-(we-x)/(w1e-(w+2)*(we-x)/(2*w+2)) ;
);
print("W doesn't converge fast enough for ",x,"( we=",we);
return(0);
Ejemplo:
default(precision,200)
x = -0.99999/exp(1)
%382 = -0.367875762377
y=LW(x)
%383 = -0.995534517079
[chk=y*exp(y);x;chk-x]
%384 =
[-0.367875762377]
[-0.367875762377]
[2.49762470622 E-163]