15#ifndef _utl_LambertW_h_ 
   16#define _utl_LambertW_h_ 
   23  template<
typename Float, 
class Tag, 
unsigned int order>
 
   26    static inline Float 
Coeff(
const Float x);
 
 
   30  template<
typename Float, 
class Tag, 
unsigned int order>
 
   32    static Float 
Recurse(
const Float term, 
const Float x)
 
 
   36    static Float 
Eval(
const Float x)
 
 
   41    static Float 
Recurse(
const Float term, 
const Float x, 
const Float y)
 
 
   43    static Float 
Eval(
const Float x, 
const Float y)
 
 
 
   48  template<
typename Float, 
class Tag>
 
   50    static Float 
Recurse(
const Float term, 
const Float x)
 
 
   52    static Float 
Eval(
const Float x)
 
 
   55    static Float 
Recurse(
const Float term, 
const Float x, 
const Float y)
 
 
   57    static Float 
Eval(
const Float x, 
const Float y)
 
 
 
   62#define HORNER_COEFF(_Tag_, _i_, _c_)                                   \ 
   63  template<typename Float> struct Polynomial<Float, _Tag_, _i_> { static Float Coeff() { return Float(_c_); } } 
 
   64#define HORNER_COEFF2(_Tag_, _i_, _c_y_)                                \ 
   65  template<typename Float> struct Polynomial<Float, _Tag_, _i_> { static Float Coeff(const Float y) { return Float(_c_y_); } } 
 
   68#define HORNER0(F, x, c0)                                                (F)(c0) 
   69#define HORNER1(F, x, c1, c0)                                 HORNER0(F, x, (F)(c1)*(x) + (F)(c0)                                ) 
   70#define HORNER2(F, x, c2, c1, c0)                             HORNER1(F, x, (F)(c2)*(x) + (F)(c1),                             c0) 
   71#define HORNER3(F, x, c3, c2, c1, c0)                         HORNER2(F, x, (F)(c3)*(x) + (F)(c2),                         c1, c0) 
   72#define HORNER4(F, x, c4, c3, c2, c1, c0)                     HORNER3(F, x, (F)(c4)*(x) + (F)(c3),                     c2, c1, c0) 
   73#define HORNER5(F, x, c5, c4, c3, c2, c1, c0)                 HORNER4(F, x, (F)(c5)*(x) + (F)(c4),                 c3, c2, c1, c0) 
   74#define HORNER6(F, x, c6, c5, c4, c3, c2, c1, c0)             HORNER5(F, x, (F)(c6)*(x) + (F)(c5),             c4, c3, c2, c1, c0) 
   75#define HORNER7(F, x, c7, c6, c5, c4, c3, c2, c1, c0)         HORNER6(F, x, (F)(c7)*(x) + (F)(c6),         c5, c4, c3, c2, c1, c0) 
   76#define HORNER8(F, x, c8, c7, c6, c5, c4, c3, c2, c1, c0)     HORNER7(F, x, (F)(c8)*(x) + (F)(c7),     c6, c5, c4, c3, c2, c1, c0) 
   77#define HORNER9(F, x, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0) HORNER8(F, x, (F)(c9)*(x) + (F)(c8), c7, c6, c5, c4, c3, c2, c1, c0) 
   82#define Y2(d1, c12, d2)                         \ 
 
   84#define Y3(d1, c12, d2, c23, d3)                \ 
   85  Y2(Y2(d1, c12, d2), c23, d3) 
 
   86#define Y4(d1, c12, d2, c23, d3, c34, d4)       \ 
   87  Y3(d1, c12, d2, c23, Y2(d3, c34, d4)) 
 
   88#define Y5(d1, c12, d2, c23, d3, c34, d4, c45, d5)  \ 
   89  Y4(Y2(d1, c12, d2), c23, d3, c34, d4, c45, d5) 
 
   90#define Y6(d1, c12, d2, c23, d3, c34, d4, c45, d5, c56, d6) \ 
   91  Y5(d1, c12, d2, c23, d3, c34, d4, c45, Y2(d5, c56, d6)) 
 
   92#define Y7(d1, c12, d2, c23, d3, c34, d4, c45, d5, c56, d6, c67, d7)    \ 
   93  Y6(d1, c12, d2, c23, Y2(d3, c34, d4), c45, d5, c56, d6, c67, d7) 
 
  120  template<
unsigned int order>
 
  155  template<
typename Float, 
int order>
 
  164  template<
typename Float, 
int branch, 
int order>
 
  167    static Float 
Step(
const Float logsx)
 
 
 
  171  template<
typename Float, 
int branch>
 
  173    static Float 
Step(
const Float logsx) { 
return logsx; }
 
 
  177  template<
typename Float, 
int branch>
 
  190      const Float logsx = log(
eSign * x);
 
  191      const Float logslogsx = log(
eSign * logsx);
 
 
 
  207  template<
typename Float>
 
  212    const Float ew = exp(w);
 
  213    const Float wew = w * ew;
 
  214    const Float wewx = wew - x;
 
  215    const Float w1 = w + 1;
 
  216    return w - wewx / (ew * w1 - (w + 2) * wewx/(2*w1));
 
 
  220  template<
typename Float>
 
  225    const Float z = log(x/w) - w;
 
  226    const Float w1 = w + 1;
 
  227    const Float q = 2 * w1 * (w1 + Float(2./3)*z);
 
  228    const Float eps = z / w1 * (q - z) / (q - 2*z);
 
  229    return w * (1 + eps);
 
 
  233  template<
typename Float>
 
  238    const Float y = x * exp(-w);
 
  239    const Float f0 = w - y;
 
  240    const Float f1 = 1 + y;
 
  241    const Float f00 = f0*f0;
 
  242    const Float f11 = f1*f1;
 
  243    const Float f0y = f0*y;
 
  244    return w - 4*f0*(6*f1*(f11 + f0y) + f00*y) / (f11*(24*f11 + 36*f0y) + f00*(6*y*y + 8*f1*y + f0y));
 
 
  250    double IterationStep(
const Float x, 
const Float w)
 
  254    template<
int n, 
class = 
void>
 
  263      static Float 
Recurse(
const Float x, 
const Float w) { 
return IterationStep(x, w); }
 
 
  269      static Float 
Recurse(
const Float x, 
const Float w) { 
return w; }
 
 
 
  277  template<
typename Float, 
int branch, 
int n>
 
  283  template<
typename Float>
 
  286    { 
return x * 
HORNER4(Float, x, 0.07066247420543414, 2.4326814530577687, 6.39672835731526, 4.663365025836821, 0.99999908757381) /
 
  287        HORNER4(Float, x, 1.2906660139511692, 7.164571775410987, 10.559985088953114, 5.66336307375819, 1); }
 
 
 
  291  template<
typename Float>
 
  294    { 
const Float y = log(Float(0.5)*x) - 2;
 
  295      return 2 + y * 
HORNER3(Float, y, 0.00006979269679670452, 0.017110368846615806, 0.19338607770900237, 0.6666648896499793) /
 
  296        HORNER2(Float, y, 0.0188060684652668, 0.23451269827133317, 1); }
 
 
 
  300  template<
typename Float>
 
  303    { 
return HORNER4(Float, x, -2793.4565508841197, -1987.3632221106518, 385.7992853617571, 277.2362778379572, -7.840776922133643) /
 
  304        HORNER4(Float, x, 280.6156995997829, 941.9414019982657, 190.64429338894644, -63.93540494358966, 1); }
 
 
 
  308  template<
typename Float>
 
  311    { 
const Float y = log(-x);
 
  313                  HORNER3(Float, y, 0.16415668298255184, -3.334873920301941, 2.4831415860003747, 4.173424474574879) /
 
  314                  HORNER3(Float, y, 0.031239411487374164, -1.2961659693400076, 4.517178492772906, 1)
 
 
 
  319  template<
typename Float>
 
  322    { 
const Float y = log(-x);
 
  324                  HORNER4(Float, y, 0.000026987243254533254, -0.007692106448267341, 0.28793461719300206, -1.5267058884647018, -0.5370669268991288) /
 
  325                  HORNER4(Float, y, 3.6006502104930343e-6, -0.0015552463555591487, 0.08801194682489769, -0.8973922357575583, 1)
 
 
 
  330  template<
typename Float>
 
  334                       HORNER4(Float, x, 988.0070769375508, 1619.8111957356814, 989.2017745708083, 266.9332506485452, 26.875022558546036) /
 
  335                       HORNER4(Float, x, -205.50469464210596, -270.0440832897079, -109.554245632316, -11.275355431307334, 1)
 
 
 
  365  LambertW<-1>(
const double x)
 
 
  388  template double LambertW<-1>(
const double x);
 
  400    case -1: 
return LambertW<-1>(x);
 
  402    default: 
return std::numeric_limits<double>::quiet_NaN();
 
 
#define HORNER3(F, x, c3, c2, c1, c0)
 
#define HORNER2(F, x, c2, c1, c0)
 
#define HORNER_COEFF(_Tag_, _i_, _c_)
 
#define HORNER_COEFF2(_Tag_, _i_, _c_y_)
 
#define HORNER4(F, x, c4, c3, c2, c1, c0)
 
#define Y5(d1, c12, d2, c23, d3, c34, d4, c45, d5)
 
#define Y7(d1, c12, d2, c23, d3, c34, d4, c45, d5, c56, d6, c67, d7)
 
static Float AsymptoticExpansion(const Float x)
 
static Float LogRecursion(const Float x)
 
static Float BranchPointExpansion(const Float x)
 
double LambertW(const double x)
 
Float FritschStep(const Float x, const Float w)
 
Float HalleyStep(const Float x, const Float w)
 
double LambertW< 0 >(const double x)
 
Float AsymptoticExpansionImpl(const Float a, const Float b)
 
Float SchroederStep(const Float x, const Float w)
 
static Float Eval(const Float x)
 
static Float Eval(const Float x, const Float y)
 
static Float Recurse(const Float term, const Float x)
 
static Float Recurse(const Float term, const Float x, const Float y)
 
static Float Recurse(const Float term, const Float x)
 
static Float EvalAlt(const Float x)
 
static Float RecurseAlt(const Float term, const Float x)
 
static Float Eval(const Float x, const Float y)
 
static Float Eval(const Float x)
 
static Float Recurse(const Float term, const Float x, const Float y)
 
static Float Recurse(const Float x, const Float w)
 
static Float Recurse(const Float x, const Float w)
 
static Float Recurse(const Float x, Float w)
 
static Float Step(const Float logsx)
 
static Float Step(const Float logsx)
 
static Float Approximation(const Float x)
 
static Float Approximation(const Float x)
 
static Float Approximation(const Float x)
 
static Float Approximation(const Float x)
 
static Float Approximation(const Float x)
 
static Float Approximation(const Float x)
 
static Float Approximation(const Float x)
 
static Float Coeff(const Float x)