MOAB
4.9.3pre
|
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