MOAB  4.9.3pre
SpecialFunctions.h
Go to the documentation of this file.
00001 // This file is part of Eigen, a lightweight C++ template library
00002 // for linear algebra.
00003 //
00004 // Copyright (C) 2015 Eugene Brevdo <[email protected]>
00005 //
00006 // This Source Code Form is subject to the terms of the Mozilla
00007 // Public License v. 2.0. If a copy of the MPL was not distributed
00008 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
00009 
00010 #ifndef EIGEN_SPECIAL_FUNCTIONS_H
00011 #define EIGEN_SPECIAL_FUNCTIONS_H
00012 
00013 namespace Eigen {
00014 namespace internal {
00015 
00016 //  Parts of this code are based on the Cephes Math Library.
00017 //
00018 //  Cephes Math Library Release 2.8:  June, 2000
00019 //  Copyright 1984, 1987, 1992, 2000 by Stephen L. Moshier
00020 //
00021 //  Permission has been kindly provided by the original author
00022 //  to incorporate the Cephes software into the Eigen codebase:
00023 //
00024 //    From: Stephen Moshier
00025 //    To: Eugene Brevdo
00026 //    Subject: Re: Permission to wrap several cephes functions in Eigen
00027 //
00028 //    Hello Eugene,
00029 //
00030 //    Thank you for writing.
00031 //
00032 //    If your licensing is similar to BSD, the formal way that has been
00033 //    handled is simply to add a statement to the effect that you are incorporating
00034 //    the Cephes software by permission of the author.
00035 //
00036 //    Good luck with your project,
00037 //    Steve
00038 
00039 namespace cephes {
00040 
00041 /* polevl (modified for Eigen)
00042  *
00043  *      Evaluate polynomial
00044  *
00045  *
00046  *
00047  * SYNOPSIS:
00048  *
00049  * int N;
00050  * Scalar x, y, coef[N+1];
00051  *
00052  * y = polevl<decltype(x), N>( x, coef);
00053  *
00054  *
00055  *
00056  * DESCRIPTION:
00057  *
00058  * Evaluates polynomial of degree N:
00059  *
00060  *                     2          N
00061  * y  =  C  + C x + C x  +...+ C x
00062  *        0    1     2          N
00063  *
00064  * Coefficients are stored in reverse order:
00065  *
00066  * coef[0] = C  , ..., coef[N] = C  .
00067  *            N                   0
00068  *
00069  *  The function p1evl() assumes that coef[N] = 1.0 and is
00070  * omitted from the array.  Its calling arguments are
00071  * otherwise the same as polevl().
00072  *
00073  *
00074  * The Eigen implementation is templatized.  For best speed, store
00075  * coef as a const array (constexpr), e.g.
00076  *
00077  * const double coef[] = {1.0, 2.0, 3.0, ...};
00078  *
00079  */
00080 template <typename Scalar, int N>
00081 struct polevl {
00082   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
00083   static Scalar run(const Scalar x, const Scalar coef[]) {
00084     EIGEN_STATIC_ASSERT((N > 0), YOU_MADE_A_PROGRAMMING_MISTAKE);
00085 
00086     return polevl<Scalar, N - 1>::run(x, coef) * x + coef[N];
00087   }
00088 };
00089 
00090 template <typename Scalar>
00091 struct polevl<Scalar, 0> {
00092   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
00093   static Scalar run(const Scalar, const Scalar coef[]) {
00094     return coef[0];
00095   }
00096 };
00097 
00098 }  // end namespace cephes
00099 
00100 /****************************************************************************
00101  * Implementation of lgamma                                                 *
00102  ****************************************************************************/
00103 
00104 template <typename Scalar>
00105 struct lgamma_impl {
00106   EIGEN_DEVICE_FUNC
00107   static EIGEN_STRONG_INLINE Scalar run(const Scalar) {
00108     EIGEN_STATIC_ASSERT((internal::is_same<Scalar, Scalar>::value == false),
00109                         THIS_TYPE_IS_NOT_SUPPORTED);
00110     return Scalar(0);
00111   }
00112 };
00113 
00114 template <typename Scalar>
00115 struct lgamma_retval {
00116   typedef Scalar type;
00117 };
00118 
00119 #ifdef EIGEN_HAS_C99_MATH
00120 template <>
00121 struct lgamma_impl<float> {
00122   EIGEN_DEVICE_FUNC
00123   static EIGEN_STRONG_INLINE float run(float x) { return ::lgammaf(x); }
00124 };
00125 
00126 template <>
00127 struct lgamma_impl<double> {
00128   EIGEN_DEVICE_FUNC
00129   static EIGEN_STRONG_INLINE double run(double x) { return ::lgamma(x); }
00130 };
00131 #endif
00132 
00133 /****************************************************************************
00134  * Implementation of digamma (psi)                                          *
00135  ****************************************************************************/
00136 
00137 template <typename Scalar>
00138 struct digamma_retval {
00139   typedef Scalar type;
00140 };
00141 
00142 #ifndef EIGEN_HAS_C99_MATH
00143 
00144 template <typename Scalar>
00145 struct digamma_impl {
00146   EIGEN_DEVICE_FUNC
00147   static Scalar run(Scalar x) {
00148     EIGEN_STATIC_ASSERT((internal::is_same<Scalar, Scalar>::value == false),
00149                         THIS_TYPE_IS_NOT_SUPPORTED);
00150     return Scalar(0);
00151   }
00152 };
00153 
00154 #else
00155 
00156 /*
00157  *
00158  * Polynomial evaluation helper for the Psi (digamma) function.
00159  *
00160  * digamma_impl_maybe_poly::run(s) evaluates the asymptotic Psi expansion for
00161  * input Scalar s, assuming s is above 10.0.
00162  *
00163  * If s is above a certain threshold for the given Scalar type, zero
00164  * is returned.  Otherwise the polynomial is evaluated with enough
00165  * coefficients for results matching Scalar machine precision.
00166  *
00167  *
00168  */
00169 template <typename Scalar>
00170 struct digamma_impl_maybe_poly {
00171   EIGEN_DEVICE_FUNC
00172   static EIGEN_STRONG_INLINE Scalar run(const Scalar) {
00173     EIGEN_STATIC_ASSERT((internal::is_same<Scalar, Scalar>::value == false),
00174                         THIS_TYPE_IS_NOT_SUPPORTED);
00175     return Scalar(0);
00176   }
00177 };
00178 
00179 
00180 template <>
00181 struct digamma_impl_maybe_poly<float> {
00182   EIGEN_DEVICE_FUNC
00183   static EIGEN_STRONG_INLINE float run(const float s) {
00184     const float A[] = {
00185       -4.16666666666666666667E-3f,
00186       3.96825396825396825397E-3f,
00187       -8.33333333333333333333E-3f,
00188       8.33333333333333333333E-2f
00189     };
00190 
00191     float z;
00192     if (s < 1.0e8f) {
00193       z = 1.0f / (s * s);
00194       return z * cephes::polevl<float, 3>::run(z, A);
00195     } else return 0.0f;
00196   }
00197 };
00198 
00199 template <>
00200 struct digamma_impl_maybe_poly<double> {
00201   EIGEN_DEVICE_FUNC
00202   static EIGEN_STRONG_INLINE double run(const double s) {
00203     const double A[] = {
00204       8.33333333333333333333E-2,
00205       -2.10927960927960927961E-2,
00206       7.57575757575757575758E-3,
00207       -4.16666666666666666667E-3,
00208       3.96825396825396825397E-3,
00209       -8.33333333333333333333E-3,
00210       8.33333333333333333333E-2
00211     };
00212 
00213     double z;
00214     if (s < 1.0e17) {
00215       z = 1.0 / (s * s);
00216       return z * cephes::polevl<double, 6>::run(z, A);
00217     }
00218     else return 0.0;
00219   }
00220 };
00221 
00222 template <typename Scalar>
00223 struct digamma_impl {
00224   EIGEN_DEVICE_FUNC
00225   static Scalar run(Scalar x) {
00226     /*
00227      *
00228      *     Psi (digamma) function (modified for Eigen)
00229      *
00230      *
00231      * SYNOPSIS:
00232      *
00233      * double x, y, psi();
00234      *
00235      * y = psi( x );
00236      *
00237      *
00238      * DESCRIPTION:
00239      *
00240      *              d      -
00241      *   psi(x)  =  -- ln | (x)
00242      *              dx
00243      *
00244      * is the logarithmic derivative of the gamma function.
00245      * For integer x,
00246      *                   n-1
00247      *                    -
00248      * psi(n) = -EUL  +   >  1/k.
00249      *                    -
00250      *                   k=1
00251      *
00252      * If x is negative, it is transformed to a positive argument by the
00253      * reflection formula  psi(1-x) = psi(x) + pi cot(pi x).
00254      * For general positive x, the argument is made greater than 10
00255      * using the recurrence  psi(x+1) = psi(x) + 1/x.
00256      * Then the following asymptotic expansion is applied:
00257      *
00258      *                           inf.   B
00259      *                            -      2k
00260      * psi(x) = log(x) - 1/2x -   >   -------
00261      *                            -        2k
00262      *                           k=1   2k x
00263      *
00264      * where the B2k are Bernoulli numbers.
00265      *
00266      * ACCURACY (float):
00267      *    Relative error (except absolute when |psi| < 1):
00268      * arithmetic   domain     # trials      peak         rms
00269      *    IEEE      0,30        30000       1.3e-15     1.4e-16
00270      *    IEEE      -30,0       40000       1.5e-15     2.2e-16
00271      *
00272      * ACCURACY (double):
00273      *    Absolute error,  relative when |psi| > 1 :
00274      * arithmetic   domain     # trials      peak         rms
00275      *    IEEE      -33,0        30000      8.2e-7      1.2e-7
00276      *    IEEE      0,33        100000      7.3e-7      7.7e-8
00277      *
00278      * ERROR MESSAGES:
00279      *     message         condition      value returned
00280      * psi singularity    x integer <=0      INFINITY
00281      */
00282 
00283     Scalar p, q, nz, s, w, y;
00284     bool negative;
00285 
00286     const Scalar maxnum = numext::numeric_limits<Scalar>::infinity();
00287     const Scalar m_pi = 3.14159265358979323846;
00288 
00289     negative = 0;
00290     nz = 0.0;
00291 
00292     const Scalar zero = 0.0;
00293     const Scalar one = 1.0;
00294     const Scalar half = 0.5;
00295 
00296     if (x <= zero) {
00297       negative = one;
00298       q = x;
00299       p = ::floor(q);
00300       if (p == q) {
00301         return maxnum;
00302       }
00303       /* Remove the zeros of tan(m_pi x)
00304        * by subtracting the nearest integer from x
00305        */
00306       nz = q - p;
00307       if (nz != half) {
00308         if (nz > half) {
00309           p += one;
00310           nz = q - p;
00311         }
00312         nz = m_pi / ::tan(m_pi * nz);
00313       }
00314       else {
00315         nz = zero;
00316       }
00317       x = one - x;
00318     }
00319 
00320     /* use the recurrence psi(x+1) = psi(x) + 1/x. */
00321     s = x;
00322     w = zero;
00323     while (s < Scalar(10)) {
00324       w += one / s;
00325       s += one;
00326     }
00327 
00328     y = digamma_impl_maybe_poly<Scalar>::run(s);
00329 
00330     y = ::log(s) - (half / s) - y - w;
00331 
00332     return (negative) ? y - nz : y;
00333   }
00334 };
00335 
00336 #endif  // EIGEN_HAS_C99_MATH
00337 
00338 /****************************************************************************
00339  * Implementation of erf                                                    *
00340  ****************************************************************************/
00341 
00342 template <typename Scalar>
00343 struct erf_impl {
00344   EIGEN_DEVICE_FUNC
00345   static EIGEN_STRONG_INLINE Scalar run(const Scalar) {
00346     EIGEN_STATIC_ASSERT((internal::is_same<Scalar, Scalar>::value == false),
00347                         THIS_TYPE_IS_NOT_SUPPORTED);
00348     return Scalar(0);
00349   }
00350 };
00351 
00352 template <typename Scalar>
00353 struct erf_retval {
00354   typedef Scalar type;
00355 };
00356 
00357 #ifdef EIGEN_HAS_C99_MATH
00358 template <>
00359 struct erf_impl<float> {
00360   EIGEN_DEVICE_FUNC
00361   static EIGEN_STRONG_INLINE float run(float x) { return ::erff(x); }
00362 };
00363 
00364 template <>
00365 struct erf_impl<double> {
00366   EIGEN_DEVICE_FUNC
00367   static EIGEN_STRONG_INLINE double run(double x) { return ::erf(x); }
00368 };
00369 #endif  // EIGEN_HAS_C99_MATH
00370 
00371 /***************************************************************************
00372 * Implementation of erfc                                                   *
00373 ****************************************************************************/
00374 
00375 template <typename Scalar>
00376 struct erfc_impl {
00377   EIGEN_DEVICE_FUNC
00378   static EIGEN_STRONG_INLINE Scalar run(const Scalar) {
00379     EIGEN_STATIC_ASSERT((internal::is_same<Scalar, Scalar>::value == false),
00380                         THIS_TYPE_IS_NOT_SUPPORTED);
00381     return Scalar(0);
00382   }
00383 };
00384 
00385 template <typename Scalar>
00386 struct erfc_retval {
00387   typedef Scalar type;
00388 };
00389 
00390 #ifdef EIGEN_HAS_C99_MATH
00391 template <>
00392 struct erfc_impl<float> {
00393   EIGEN_DEVICE_FUNC
00394   static EIGEN_STRONG_INLINE float run(const float x) { return ::erfcf(x); }
00395 };
00396 
00397 template <>
00398 struct erfc_impl<double> {
00399   EIGEN_DEVICE_FUNC
00400   static EIGEN_STRONG_INLINE double run(const double x) { return ::erfc(x); }
00401 };
00402 #endif  // EIGEN_HAS_C99_MATH
00403 
00404 }  // end namespace internal
00405 
00406 namespace numext {
00407 
00408 template <typename Scalar>
00409 EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(lgamma, Scalar)
00410     lgamma(const Scalar& x) {
00411   return EIGEN_MATHFUNC_IMPL(lgamma, Scalar)::run(x);
00412 }
00413 
00414 template <typename Scalar>
00415 EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(digamma, Scalar)
00416     digamma(const Scalar& x) {
00417   return EIGEN_MATHFUNC_IMPL(digamma, Scalar)::run(x);
00418 }
00419 
00420 template <typename Scalar>
00421 EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(erf, Scalar)
00422     erf(const Scalar& x) {
00423   return EIGEN_MATHFUNC_IMPL(erf, Scalar)::run(x);
00424 }
00425 
00426 template <typename Scalar>
00427 EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(erfc, Scalar)
00428     erfc(const Scalar& x) {
00429   return EIGEN_MATHFUNC_IMPL(erfc, Scalar)::run(x);
00430 }
00431 
00432 }  // end namespace numext
00433 
00434 }  // end namespace Eigen
00435 
00436 #endif  // EIGEN_SPECIAL_FUNCTIONS_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines