xref: /aosp_15_r20/external/eigen/unsupported/Eigen/src/SpecialFunctions/SpecialFunctionsImpl.h (revision bf2c37156dfe67e5dfebd6d394bad8b2ab5804d4)
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2015 Eugene Brevdo <[email protected]>
5 //
6 // This Source Code Form is subject to the terms of the Mozilla
7 // Public License v. 2.0. If a copy of the MPL was not distributed
8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 
10 #ifndef EIGEN_SPECIAL_FUNCTIONS_H
11 #define EIGEN_SPECIAL_FUNCTIONS_H
12 
13 namespace Eigen {
14 namespace internal {
15 
16 //  Parts of this code are based on the Cephes Math Library.
17 //
18 //  Cephes Math Library Release 2.8:  June, 2000
19 //  Copyright 1984, 1987, 1992, 2000 by Stephen L. Moshier
20 //
21 //  Permission has been kindly provided by the original author
22 //  to incorporate the Cephes software into the Eigen codebase:
23 //
24 //    From: Stephen Moshier
25 //    To: Eugene Brevdo
26 //    Subject: Re: Permission to wrap several cephes functions in Eigen
27 //
28 //    Hello Eugene,
29 //
30 //    Thank you for writing.
31 //
32 //    If your licensing is similar to BSD, the formal way that has been
33 //    handled is simply to add a statement to the effect that you are incorporating
34 //    the Cephes software by permission of the author.
35 //
36 //    Good luck with your project,
37 //    Steve
38 
39 
40 /****************************************************************************
41  * Implementation of lgamma, requires C++11/C99                             *
42  ****************************************************************************/
43 
44 template <typename Scalar>
45 struct lgamma_impl {
46   EIGEN_DEVICE_FUNC
runlgamma_impl47   static EIGEN_STRONG_INLINE Scalar run(const Scalar) {
48     EIGEN_STATIC_ASSERT((internal::is_same<Scalar, Scalar>::value == false),
49                         THIS_TYPE_IS_NOT_SUPPORTED);
50     return Scalar(0);
51   }
52 };
53 
54 template <typename Scalar>
55 struct lgamma_retval {
56   typedef Scalar type;
57 };
58 
59 #if EIGEN_HAS_C99_MATH
60 // Since glibc 2.19
61 #if defined(__GLIBC__) && ((__GLIBC__>=2 && __GLIBC_MINOR__ >= 19) || __GLIBC__>2) \
62  && (defined(_DEFAULT_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE))
63 #define EIGEN_HAS_LGAMMA_R
64 #endif
65 
66 // Glibc versions before 2.19
67 #if defined(__GLIBC__) && ((__GLIBC__==2 && __GLIBC_MINOR__ < 19) || __GLIBC__<2) \
68  && (defined(_BSD_SOURCE) || defined(_SVID_SOURCE))
69 #define EIGEN_HAS_LGAMMA_R
70 #endif
71 
72 template <>
73 struct lgamma_impl<float> {
74   EIGEN_DEVICE_FUNC
75   static EIGEN_STRONG_INLINE float run(float x) {
76 #if !defined(EIGEN_GPU_COMPILE_PHASE) && defined (EIGEN_HAS_LGAMMA_R) && !defined(__APPLE__)
77     int dummy;
78     return ::lgammaf_r(x, &dummy);
79 #elif defined(SYCL_DEVICE_ONLY)
80     return cl::sycl::lgamma(x);
81 #else
82     return ::lgammaf(x);
83 #endif
84   }
85 };
86 
87 template <>
88 struct lgamma_impl<double> {
89   EIGEN_DEVICE_FUNC
90   static EIGEN_STRONG_INLINE double run(double x) {
91 #if !defined(EIGEN_GPU_COMPILE_PHASE) && defined(EIGEN_HAS_LGAMMA_R) && !defined(__APPLE__)
92     int dummy;
93     return ::lgamma_r(x, &dummy);
94 #elif defined(SYCL_DEVICE_ONLY)
95     return cl::sycl::lgamma(x);
96 #else
97     return ::lgamma(x);
98 #endif
99   }
100 };
101 
102 #undef EIGEN_HAS_LGAMMA_R
103 #endif
104 
105 /****************************************************************************
106  * Implementation of digamma (psi), based on Cephes                         *
107  ****************************************************************************/
108 
109 template <typename Scalar>
110 struct digamma_retval {
111   typedef Scalar type;
112 };
113 
114 /*
115  *
116  * Polynomial evaluation helper for the Psi (digamma) function.
117  *
118  * digamma_impl_maybe_poly::run(s) evaluates the asymptotic Psi expansion for
119  * input Scalar s, assuming s is above 10.0.
120  *
121  * If s is above a certain threshold for the given Scalar type, zero
122  * is returned.  Otherwise the polynomial is evaluated with enough
123  * coefficients for results matching Scalar machine precision.
124  *
125  *
126  */
127 template <typename Scalar>
128 struct digamma_impl_maybe_poly {
129   EIGEN_DEVICE_FUNC
130   static EIGEN_STRONG_INLINE Scalar run(const Scalar) {
131     EIGEN_STATIC_ASSERT((internal::is_same<Scalar, Scalar>::value == false),
132                         THIS_TYPE_IS_NOT_SUPPORTED);
133     return Scalar(0);
134   }
135 };
136 
137 
138 template <>
139 struct digamma_impl_maybe_poly<float> {
140   EIGEN_DEVICE_FUNC
141   static EIGEN_STRONG_INLINE float run(const float s) {
142     const float A[] = {
143       -4.16666666666666666667E-3f,
144       3.96825396825396825397E-3f,
145       -8.33333333333333333333E-3f,
146       8.33333333333333333333E-2f
147     };
148 
149     float z;
150     if (s < 1.0e8f) {
151       z = 1.0f / (s * s);
152       return z * internal::ppolevl<float, 3>::run(z, A);
153     } else return 0.0f;
154   }
155 };
156 
157 template <>
158 struct digamma_impl_maybe_poly<double> {
159   EIGEN_DEVICE_FUNC
160   static EIGEN_STRONG_INLINE double run(const double s) {
161     const double A[] = {
162       8.33333333333333333333E-2,
163       -2.10927960927960927961E-2,
164       7.57575757575757575758E-3,
165       -4.16666666666666666667E-3,
166       3.96825396825396825397E-3,
167       -8.33333333333333333333E-3,
168       8.33333333333333333333E-2
169     };
170 
171     double z;
172     if (s < 1.0e17) {
173       z = 1.0 / (s * s);
174       return z * internal::ppolevl<double, 6>::run(z, A);
175     }
176     else return 0.0;
177   }
178 };
179 
180 template <typename Scalar>
181 struct digamma_impl {
182   EIGEN_DEVICE_FUNC
183   static Scalar run(Scalar x) {
184     /*
185      *
186      *     Psi (digamma) function (modified for Eigen)
187      *
188      *
189      * SYNOPSIS:
190      *
191      * double x, y, psi();
192      *
193      * y = psi( x );
194      *
195      *
196      * DESCRIPTION:
197      *
198      *              d      -
199      *   psi(x)  =  -- ln | (x)
200      *              dx
201      *
202      * is the logarithmic derivative of the gamma function.
203      * For integer x,
204      *                   n-1
205      *                    -
206      * psi(n) = -EUL  +   >  1/k.
207      *                    -
208      *                   k=1
209      *
210      * If x is negative, it is transformed to a positive argument by the
211      * reflection formula  psi(1-x) = psi(x) + pi cot(pi x).
212      * For general positive x, the argument is made greater than 10
213      * using the recurrence  psi(x+1) = psi(x) + 1/x.
214      * Then the following asymptotic expansion is applied:
215      *
216      *                           inf.   B
217      *                            -      2k
218      * psi(x) = log(x) - 1/2x -   >   -------
219      *                            -        2k
220      *                           k=1   2k x
221      *
222      * where the B2k are Bernoulli numbers.
223      *
224      * ACCURACY (float):
225      *    Relative error (except absolute when |psi| < 1):
226      * arithmetic   domain     # trials      peak         rms
227      *    IEEE      0,30        30000       1.3e-15     1.4e-16
228      *    IEEE      -30,0       40000       1.5e-15     2.2e-16
229      *
230      * ACCURACY (double):
231      *    Absolute error,  relative when |psi| > 1 :
232      * arithmetic   domain     # trials      peak         rms
233      *    IEEE      -33,0        30000      8.2e-7      1.2e-7
234      *    IEEE      0,33        100000      7.3e-7      7.7e-8
235      *
236      * ERROR MESSAGES:
237      *     message         condition      value returned
238      * psi singularity    x integer <=0      INFINITY
239      */
240 
241     Scalar p, q, nz, s, w, y;
242     bool negative = false;
243 
244     const Scalar nan = NumTraits<Scalar>::quiet_NaN();
245     const Scalar m_pi = Scalar(EIGEN_PI);
246 
247     const Scalar zero = Scalar(0);
248     const Scalar one = Scalar(1);
249     const Scalar half = Scalar(0.5);
250     nz = zero;
251 
252     if (x <= zero) {
253       negative = true;
254       q = x;
255       p = numext::floor(q);
256       if (p == q) {
257         return nan;
258       }
259       /* Remove the zeros of tan(m_pi x)
260        * by subtracting the nearest integer from x
261        */
262       nz = q - p;
263       if (nz != half) {
264         if (nz > half) {
265           p += one;
266           nz = q - p;
267         }
268         nz = m_pi / numext::tan(m_pi * nz);
269       }
270       else {
271         nz = zero;
272       }
273       x = one - x;
274     }
275 
276     /* use the recurrence psi(x+1) = psi(x) + 1/x. */
277     s = x;
278     w = zero;
279     while (s < Scalar(10)) {
280       w += one / s;
281       s += one;
282     }
283 
284     y = digamma_impl_maybe_poly<Scalar>::run(s);
285 
286     y = numext::log(s) - (half / s) - y - w;
287 
288     return (negative) ? y - nz : y;
289   }
290 };
291 
292 /****************************************************************************
293  * Implementation of erf, requires C++11/C99                                *
294  ****************************************************************************/
295 
296 /** \internal \returns the error function of \a a (coeff-wise)
297     Doesn't do anything fancy, just a 13/8-degree rational interpolant which
298     is accurate up to a couple of ulp in the range [-4, 4], outside of which
299     fl(erf(x)) = +/-1.
300 
301     This implementation works on both scalars and Ts.
302 */
303 template <typename T>
304 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T generic_fast_erf_float(const T& a_x) {
305   // Clamp the inputs to the range [-4, 4] since anything outside
306   // this range is +/-1.0f in single-precision.
307   const T plus_4 = pset1<T>(4.f);
308   const T minus_4 = pset1<T>(-4.f);
309   const T x = pmax(pmin(a_x, plus_4), minus_4);
310   // The monomial coefficients of the numerator polynomial (odd).
311   const T alpha_1 = pset1<T>(-1.60960333262415e-02f);
312   const T alpha_3 = pset1<T>(-2.95459980854025e-03f);
313   const T alpha_5 = pset1<T>(-7.34990630326855e-04f);
314   const T alpha_7 = pset1<T>(-5.69250639462346e-05f);
315   const T alpha_9 = pset1<T>(-2.10102402082508e-06f);
316   const T alpha_11 = pset1<T>(2.77068142495902e-08f);
317   const T alpha_13 = pset1<T>(-2.72614225801306e-10f);
318 
319   // The monomial coefficients of the denominator polynomial (even).
320   const T beta_0 = pset1<T>(-1.42647390514189e-02f);
321   const T beta_2 = pset1<T>(-7.37332916720468e-03f);
322   const T beta_4 = pset1<T>(-1.68282697438203e-03f);
323   const T beta_6 = pset1<T>(-2.13374055278905e-04f);
324   const T beta_8 = pset1<T>(-1.45660718464996e-05f);
325 
326   // Since the polynomials are odd/even, we need x^2.
327   const T x2 = pmul(x, x);
328 
329   // Evaluate the numerator polynomial p.
330   T p = pmadd(x2, alpha_13, alpha_11);
331   p = pmadd(x2, p, alpha_9);
332   p = pmadd(x2, p, alpha_7);
333   p = pmadd(x2, p, alpha_5);
334   p = pmadd(x2, p, alpha_3);
335   p = pmadd(x2, p, alpha_1);
336   p = pmul(x, p);
337 
338   // Evaluate the denominator polynomial p.
339   T q = pmadd(x2, beta_8, beta_6);
340   q = pmadd(x2, q, beta_4);
341   q = pmadd(x2, q, beta_2);
342   q = pmadd(x2, q, beta_0);
343 
344   // Divide the numerator by the denominator.
345   return pdiv(p, q);
346 }
347 
348 template <typename T>
349 struct erf_impl {
350   EIGEN_DEVICE_FUNC
351   static EIGEN_STRONG_INLINE T run(const T& x) {
352     return generic_fast_erf_float(x);
353   }
354 };
355 
356 template <typename Scalar>
357 struct erf_retval {
358   typedef Scalar type;
359 };
360 
361 #if EIGEN_HAS_C99_MATH
362 template <>
363 struct erf_impl<float> {
364   EIGEN_DEVICE_FUNC
365   static EIGEN_STRONG_INLINE float run(float x) {
366 #if defined(SYCL_DEVICE_ONLY)
367     return cl::sycl::erf(x);
368 #else
369     return generic_fast_erf_float(x);
370 #endif
371   }
372 };
373 
374 template <>
375 struct erf_impl<double> {
376   EIGEN_DEVICE_FUNC
377   static EIGEN_STRONG_INLINE double run(double x) {
378 #if defined(SYCL_DEVICE_ONLY)
379     return cl::sycl::erf(x);
380 #else
381     return ::erf(x);
382 #endif
383   }
384 };
385 #endif  // EIGEN_HAS_C99_MATH
386 
387 /***************************************************************************
388 * Implementation of erfc, requires C++11/C99                               *
389 ****************************************************************************/
390 
391 template <typename Scalar>
392 struct erfc_impl {
393   EIGEN_DEVICE_FUNC
394   static EIGEN_STRONG_INLINE Scalar run(const Scalar) {
395     EIGEN_STATIC_ASSERT((internal::is_same<Scalar, Scalar>::value == false),
396                         THIS_TYPE_IS_NOT_SUPPORTED);
397     return Scalar(0);
398   }
399 };
400 
401 template <typename Scalar>
402 struct erfc_retval {
403   typedef Scalar type;
404 };
405 
406 #if EIGEN_HAS_C99_MATH
407 template <>
408 struct erfc_impl<float> {
409   EIGEN_DEVICE_FUNC
410   static EIGEN_STRONG_INLINE float run(const float x) {
411 #if defined(SYCL_DEVICE_ONLY)
412     return cl::sycl::erfc(x);
413 #else
414     return ::erfcf(x);
415 #endif
416   }
417 };
418 
419 template <>
420 struct erfc_impl<double> {
421   EIGEN_DEVICE_FUNC
422   static EIGEN_STRONG_INLINE double run(const double x) {
423 #if defined(SYCL_DEVICE_ONLY)
424     return cl::sycl::erfc(x);
425 #else
426     return ::erfc(x);
427 #endif
428   }
429 };
430 #endif  // EIGEN_HAS_C99_MATH
431 
432 
433 /***************************************************************************
434 * Implementation of ndtri.                                                 *
435 ****************************************************************************/
436 
437 /* Inverse of Normal distribution function (modified for Eigen).
438  *
439  *
440  * SYNOPSIS:
441  *
442  * double x, y, ndtri();
443  *
444  * x = ndtri( y );
445  *
446  *
447  *
448  * DESCRIPTION:
449  *
450  * Returns the argument, x, for which the area under the
451  * Gaussian probability density function (integrated from
452  * minus infinity to x) is equal to y.
453  *
454  *
455  * For small arguments 0 < y < exp(-2), the program computes
456  * z = sqrt( -2.0 * log(y) );  then the approximation is
457  * x = z - log(z)/z  - (1/z) P(1/z) / Q(1/z).
458  * There are two rational functions P/Q, one for 0 < y < exp(-32)
459  * and the other for y up to exp(-2).  For larger arguments,
460  * w = y - 0.5, and  x/sqrt(2pi) = w + w**3 R(w**2)/S(w**2)).
461  *
462  *
463  * ACCURACY:
464  *
465  *                      Relative error:
466  * arithmetic   domain        # trials      peak         rms
467  *    DEC      0.125, 1         5500       9.5e-17     2.1e-17
468  *    DEC      6e-39, 0.135     3500       5.7e-17     1.3e-17
469  *    IEEE     0.125, 1        20000       7.2e-16     1.3e-16
470  *    IEEE     3e-308, 0.135   50000       4.6e-16     9.8e-17
471  *
472  *
473  * ERROR MESSAGES:
474  *
475  *   message         condition    value returned
476  * ndtri domain       x <= 0        -MAXNUM
477  * ndtri domain       x >= 1         MAXNUM
478  *
479  */
480  /*
481    Cephes Math Library Release 2.2: June, 1992
482    Copyright 1985, 1987, 1992 by Stephen L. Moshier
483    Direct inquiries to 30 Frost Street, Cambridge, MA 02140
484  */
485 
486 
487 // TODO: Add a cheaper approximation for float.
488 
489 
490 template<typename T>
491 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T flipsign(
492     const T& should_flipsign, const T& x) {
493   typedef typename unpacket_traits<T>::type Scalar;
494   const T sign_mask = pset1<T>(Scalar(-0.0));
495   T sign_bit = pand<T>(should_flipsign, sign_mask);
496   return pxor<T>(sign_bit, x);
497 }
498 
499 template<>
500 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double flipsign<double>(
501     const double& should_flipsign, const double& x) {
502   return should_flipsign == 0 ? x : -x;
503 }
504 
505 template<>
506 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float flipsign<float>(
507     const float& should_flipsign, const float& x) {
508   return should_flipsign == 0 ? x : -x;
509 }
510 
511 // We split this computation in to two so that in the scalar path
512 // only one branch is evaluated (due to our template specialization of pselect
513 // being an if statement.)
514 
515 template <typename T, typename ScalarType>
516 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T generic_ndtri_gt_exp_neg_two(const T& b) {
517   const ScalarType p0[] = {
518     ScalarType(-5.99633501014107895267e1),
519     ScalarType(9.80010754185999661536e1),
520     ScalarType(-5.66762857469070293439e1),
521     ScalarType(1.39312609387279679503e1),
522     ScalarType(-1.23916583867381258016e0)
523   };
524   const ScalarType q0[] = {
525     ScalarType(1.0),
526     ScalarType(1.95448858338141759834e0),
527     ScalarType(4.67627912898881538453e0),
528     ScalarType(8.63602421390890590575e1),
529     ScalarType(-2.25462687854119370527e2),
530     ScalarType(2.00260212380060660359e2),
531     ScalarType(-8.20372256168333339912e1),
532     ScalarType(1.59056225126211695515e1),
533     ScalarType(-1.18331621121330003142e0)
534   };
535   const T sqrt2pi = pset1<T>(ScalarType(2.50662827463100050242e0));
536   const T half = pset1<T>(ScalarType(0.5));
537   T c, c2, ndtri_gt_exp_neg_two;
538 
539   c = psub(b, half);
540   c2 = pmul(c, c);
541   ndtri_gt_exp_neg_two = pmadd(c, pmul(
542       c2, pdiv(
543           internal::ppolevl<T, 4>::run(c2, p0),
544           internal::ppolevl<T, 8>::run(c2, q0))), c);
545   return pmul(ndtri_gt_exp_neg_two, sqrt2pi);
546 }
547 
548 template <typename T, typename ScalarType>
549 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T generic_ndtri_lt_exp_neg_two(
550     const T& b, const T& should_flipsign) {
551   /* Approximation for interval z = sqrt(-2 log a ) between 2 and 8
552    * i.e., a between exp(-2) = .135 and exp(-32) = 1.27e-14.
553    */
554   const ScalarType p1[] = {
555     ScalarType(4.05544892305962419923e0),
556     ScalarType(3.15251094599893866154e1),
557     ScalarType(5.71628192246421288162e1),
558     ScalarType(4.40805073893200834700e1),
559     ScalarType(1.46849561928858024014e1),
560     ScalarType(2.18663306850790267539e0),
561     ScalarType(-1.40256079171354495875e-1),
562     ScalarType(-3.50424626827848203418e-2),
563     ScalarType(-8.57456785154685413611e-4)
564   };
565   const ScalarType q1[] = {
566     ScalarType(1.0),
567     ScalarType(1.57799883256466749731e1),
568     ScalarType(4.53907635128879210584e1),
569     ScalarType(4.13172038254672030440e1),
570     ScalarType(1.50425385692907503408e1),
571     ScalarType(2.50464946208309415979e0),
572     ScalarType(-1.42182922854787788574e-1),
573     ScalarType(-3.80806407691578277194e-2),
574     ScalarType(-9.33259480895457427372e-4)
575   };
576   /* Approximation for interval z = sqrt(-2 log a ) between 8 and 64
577    * i.e., a between exp(-32) = 1.27e-14 and exp(-2048) = 3.67e-890.
578    */
579   const ScalarType p2[] = {
580     ScalarType(3.23774891776946035970e0),
581     ScalarType(6.91522889068984211695e0),
582     ScalarType(3.93881025292474443415e0),
583     ScalarType(1.33303460815807542389e0),
584     ScalarType(2.01485389549179081538e-1),
585     ScalarType(1.23716634817820021358e-2),
586     ScalarType(3.01581553508235416007e-4),
587     ScalarType(2.65806974686737550832e-6),
588     ScalarType(6.23974539184983293730e-9)
589   };
590   const ScalarType q2[] = {
591     ScalarType(1.0),
592     ScalarType(6.02427039364742014255e0),
593     ScalarType(3.67983563856160859403e0),
594     ScalarType(1.37702099489081330271e0),
595     ScalarType(2.16236993594496635890e-1),
596     ScalarType(1.34204006088543189037e-2),
597     ScalarType(3.28014464682127739104e-4),
598     ScalarType(2.89247864745380683936e-6),
599     ScalarType(6.79019408009981274425e-9)
600   };
601   const T eight = pset1<T>(ScalarType(8.0));
602   const T one = pset1<T>(ScalarType(1));
603   const T neg_two = pset1<T>(ScalarType(-2));
604   T x, x0, x1, z;
605 
606   x = psqrt(pmul(neg_two, plog(b)));
607   x0 = psub(x, pdiv(plog(x), x));
608   z = pdiv(one, x);
609   x1 = pmul(
610       z, pselect(
611           pcmp_lt(x, eight),
612           pdiv(internal::ppolevl<T, 8>::run(z, p1),
613                internal::ppolevl<T, 8>::run(z, q1)),
614           pdiv(internal::ppolevl<T, 8>::run(z, p2),
615                internal::ppolevl<T, 8>::run(z, q2))));
616   return flipsign(should_flipsign, psub(x0, x1));
617 }
618 
619 template <typename T, typename ScalarType>
620 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
621 T generic_ndtri(const T& a) {
622   const T maxnum = pset1<T>(NumTraits<ScalarType>::infinity());
623   const T neg_maxnum = pset1<T>(-NumTraits<ScalarType>::infinity());
624 
625   const T zero = pset1<T>(ScalarType(0));
626   const T one = pset1<T>(ScalarType(1));
627   // exp(-2)
628   const T exp_neg_two = pset1<T>(ScalarType(0.13533528323661269189));
629   T b, ndtri, should_flipsign;
630 
631   should_flipsign = pcmp_le(a, psub(one, exp_neg_two));
632   b = pselect(should_flipsign, a, psub(one, a));
633 
634   ndtri = pselect(
635       pcmp_lt(exp_neg_two, b),
636       generic_ndtri_gt_exp_neg_two<T, ScalarType>(b),
637       generic_ndtri_lt_exp_neg_two<T, ScalarType>(b, should_flipsign));
638 
639   return pselect(
640       pcmp_le(a, zero), neg_maxnum,
641       pselect(pcmp_le(one, a), maxnum, ndtri));
642 }
643 
644 template <typename Scalar>
645 struct ndtri_retval {
646   typedef Scalar type;
647 };
648 
649 #if !EIGEN_HAS_C99_MATH
650 
651 template <typename Scalar>
652 struct ndtri_impl {
653   EIGEN_DEVICE_FUNC
654   static EIGEN_STRONG_INLINE Scalar run(const Scalar) {
655     EIGEN_STATIC_ASSERT((internal::is_same<Scalar, Scalar>::value == false),
656                         THIS_TYPE_IS_NOT_SUPPORTED);
657     return Scalar(0);
658   }
659 };
660 
661 # else
662 
663 template <typename Scalar>
664 struct ndtri_impl {
665   EIGEN_DEVICE_FUNC
666   static EIGEN_STRONG_INLINE Scalar run(const Scalar x) {
667     return generic_ndtri<Scalar, Scalar>(x);
668   }
669 };
670 
671 #endif  // EIGEN_HAS_C99_MATH
672 
673 
674 /**************************************************************************************************************
675  * Implementation of igammac (complemented incomplete gamma integral), based on Cephes but requires C++11/C99 *
676  **************************************************************************************************************/
677 
678 template <typename Scalar>
679 struct igammac_retval {
680   typedef Scalar type;
681 };
682 
683 // NOTE: cephes_helper is also used to implement zeta
684 template <typename Scalar>
685 struct cephes_helper {
686   EIGEN_DEVICE_FUNC
687   static EIGEN_STRONG_INLINE Scalar machep() { assert(false && "machep not supported for this type"); return 0.0; }
688   EIGEN_DEVICE_FUNC
689   static EIGEN_STRONG_INLINE Scalar big() { assert(false && "big not supported for this type"); return 0.0; }
690   EIGEN_DEVICE_FUNC
691   static EIGEN_STRONG_INLINE Scalar biginv() { assert(false && "biginv not supported for this type"); return 0.0; }
692 };
693 
694 template <>
695 struct cephes_helper<float> {
696   EIGEN_DEVICE_FUNC
697   static EIGEN_STRONG_INLINE float machep() {
698     return NumTraits<float>::epsilon() / 2;  // 1.0 - machep == 1.0
699   }
700   EIGEN_DEVICE_FUNC
701   static EIGEN_STRONG_INLINE float big() {
702     // use epsneg (1.0 - epsneg == 1.0)
703     return 1.0f / (NumTraits<float>::epsilon() / 2);
704   }
705   EIGEN_DEVICE_FUNC
706   static EIGEN_STRONG_INLINE float biginv() {
707     // epsneg
708     return machep();
709   }
710 };
711 
712 template <>
713 struct cephes_helper<double> {
714   EIGEN_DEVICE_FUNC
715   static EIGEN_STRONG_INLINE double machep() {
716     return NumTraits<double>::epsilon() / 2;  // 1.0 - machep == 1.0
717   }
718   EIGEN_DEVICE_FUNC
719   static EIGEN_STRONG_INLINE double big() {
720     return 1.0 / NumTraits<double>::epsilon();
721   }
722   EIGEN_DEVICE_FUNC
723   static EIGEN_STRONG_INLINE double biginv() {
724     // inverse of eps
725     return NumTraits<double>::epsilon();
726   }
727 };
728 
729 enum IgammaComputationMode { VALUE, DERIVATIVE, SAMPLE_DERIVATIVE };
730 
731 template <typename Scalar>
732 EIGEN_DEVICE_FUNC
733 static EIGEN_STRONG_INLINE Scalar main_igamma_term(Scalar a, Scalar x) {
734     /* Compute  x**a * exp(-x) / gamma(a)  */
735     Scalar logax = a * numext::log(x) - x - lgamma_impl<Scalar>::run(a);
736     if (logax < -numext::log(NumTraits<Scalar>::highest()) ||
737         // Assuming x and a aren't Nan.
738         (numext::isnan)(logax)) {
739       return Scalar(0);
740     }
741     return numext::exp(logax);
742 }
743 
744 template <typename Scalar, IgammaComputationMode mode>
745 EIGEN_DEVICE_FUNC
746 int igamma_num_iterations() {
747   /* Returns the maximum number of internal iterations for igamma computation.
748    */
749   if (mode == VALUE) {
750     return 2000;
751   }
752 
753   if (internal::is_same<Scalar, float>::value) {
754     return 200;
755   } else if (internal::is_same<Scalar, double>::value) {
756     return 500;
757   } else {
758     return 2000;
759   }
760 }
761 
762 template <typename Scalar, IgammaComputationMode mode>
763 struct igammac_cf_impl {
764   /* Computes igamc(a, x) or derivative (depending on the mode)
765    * using the continued fraction expansion of the complementary
766    * incomplete Gamma function.
767    *
768    * Preconditions:
769    *   a > 0
770    *   x >= 1
771    *   x >= a
772    */
773   EIGEN_DEVICE_FUNC
774   static Scalar run(Scalar a, Scalar x) {
775     const Scalar zero = 0;
776     const Scalar one = 1;
777     const Scalar two = 2;
778     const Scalar machep = cephes_helper<Scalar>::machep();
779     const Scalar big = cephes_helper<Scalar>::big();
780     const Scalar biginv = cephes_helper<Scalar>::biginv();
781 
782     if ((numext::isinf)(x)) {
783       return zero;
784     }
785 
786     Scalar ax = main_igamma_term<Scalar>(a, x);
787     // This is independent of mode. If this value is zero,
788     // then the function value is zero. If the function value is zero,
789     // then we are in a neighborhood where the function value evalutes to zero,
790     // so the derivative is zero.
791     if (ax == zero) {
792       return zero;
793     }
794 
795     // continued fraction
796     Scalar y = one - a;
797     Scalar z = x + y + one;
798     Scalar c = zero;
799     Scalar pkm2 = one;
800     Scalar qkm2 = x;
801     Scalar pkm1 = x + one;
802     Scalar qkm1 = z * x;
803     Scalar ans = pkm1 / qkm1;
804 
805     Scalar dpkm2_da = zero;
806     Scalar dqkm2_da = zero;
807     Scalar dpkm1_da = zero;
808     Scalar dqkm1_da = -x;
809     Scalar dans_da = (dpkm1_da - ans * dqkm1_da) / qkm1;
810 
811     for (int i = 0; i < igamma_num_iterations<Scalar, mode>(); i++) {
812       c += one;
813       y += one;
814       z += two;
815 
816       Scalar yc = y * c;
817       Scalar pk = pkm1 * z - pkm2 * yc;
818       Scalar qk = qkm1 * z - qkm2 * yc;
819 
820       Scalar dpk_da = dpkm1_da * z - pkm1 - dpkm2_da * yc + pkm2 * c;
821       Scalar dqk_da = dqkm1_da * z - qkm1 - dqkm2_da * yc + qkm2 * c;
822 
823       if (qk != zero) {
824         Scalar ans_prev = ans;
825         ans = pk / qk;
826 
827         Scalar dans_da_prev = dans_da;
828         dans_da = (dpk_da - ans * dqk_da) / qk;
829 
830         if (mode == VALUE) {
831           if (numext::abs(ans_prev - ans) <= machep * numext::abs(ans)) {
832             break;
833           }
834         } else {
835           if (numext::abs(dans_da - dans_da_prev) <= machep) {
836             break;
837           }
838         }
839       }
840 
841       pkm2 = pkm1;
842       pkm1 = pk;
843       qkm2 = qkm1;
844       qkm1 = qk;
845 
846       dpkm2_da = dpkm1_da;
847       dpkm1_da = dpk_da;
848       dqkm2_da = dqkm1_da;
849       dqkm1_da = dqk_da;
850 
851       if (numext::abs(pk) > big) {
852         pkm2 *= biginv;
853         pkm1 *= biginv;
854         qkm2 *= biginv;
855         qkm1 *= biginv;
856 
857         dpkm2_da *= biginv;
858         dpkm1_da *= biginv;
859         dqkm2_da *= biginv;
860         dqkm1_da *= biginv;
861       }
862     }
863 
864     /* Compute  x**a * exp(-x) / gamma(a)  */
865     Scalar dlogax_da = numext::log(x) - digamma_impl<Scalar>::run(a);
866     Scalar dax_da = ax * dlogax_da;
867 
868     switch (mode) {
869       case VALUE:
870         return ans * ax;
871       case DERIVATIVE:
872         return ans * dax_da + dans_da * ax;
873       case SAMPLE_DERIVATIVE:
874       default: // this is needed to suppress clang warning
875         return -(dans_da + ans * dlogax_da) * x;
876     }
877   }
878 };
879 
880 template <typename Scalar, IgammaComputationMode mode>
881 struct igamma_series_impl {
882   /* Computes igam(a, x) or its derivative (depending on the mode)
883    * using the series expansion of the incomplete Gamma function.
884    *
885    * Preconditions:
886    *   x > 0
887    *   a > 0
888    *   !(x > 1 && x > a)
889    */
890   EIGEN_DEVICE_FUNC
891   static Scalar run(Scalar a, Scalar x) {
892     const Scalar zero = 0;
893     const Scalar one = 1;
894     const Scalar machep = cephes_helper<Scalar>::machep();
895 
896     Scalar ax = main_igamma_term<Scalar>(a, x);
897 
898     // This is independent of mode. If this value is zero,
899     // then the function value is zero. If the function value is zero,
900     // then we are in a neighborhood where the function value evalutes to zero,
901     // so the derivative is zero.
902     if (ax == zero) {
903       return zero;
904     }
905 
906     ax /= a;
907 
908     /* power series */
909     Scalar r = a;
910     Scalar c = one;
911     Scalar ans = one;
912 
913     Scalar dc_da = zero;
914     Scalar dans_da = zero;
915 
916     for (int i = 0; i < igamma_num_iterations<Scalar, mode>(); i++) {
917       r += one;
918       Scalar term = x / r;
919       Scalar dterm_da = -x / (r * r);
920       dc_da = term * dc_da + dterm_da * c;
921       dans_da += dc_da;
922       c *= term;
923       ans += c;
924 
925       if (mode == VALUE) {
926         if (c <= machep * ans) {
927           break;
928         }
929       } else {
930         if (numext::abs(dc_da) <= machep * numext::abs(dans_da)) {
931           break;
932         }
933       }
934     }
935 
936     Scalar dlogax_da = numext::log(x) - digamma_impl<Scalar>::run(a + one);
937     Scalar dax_da = ax * dlogax_da;
938 
939     switch (mode) {
940       case VALUE:
941         return ans * ax;
942       case DERIVATIVE:
943         return ans * dax_da + dans_da * ax;
944       case SAMPLE_DERIVATIVE:
945       default: // this is needed to suppress clang warning
946         return -(dans_da + ans * dlogax_da) * x / a;
947     }
948   }
949 };
950 
951 #if !EIGEN_HAS_C99_MATH
952 
953 template <typename Scalar>
954 struct igammac_impl {
955   EIGEN_DEVICE_FUNC
956   static Scalar run(Scalar a, Scalar x) {
957     EIGEN_STATIC_ASSERT((internal::is_same<Scalar, Scalar>::value == false),
958                         THIS_TYPE_IS_NOT_SUPPORTED);
959     return Scalar(0);
960   }
961 };
962 
963 #else
964 
965 template <typename Scalar>
966 struct igammac_impl {
967   EIGEN_DEVICE_FUNC
968   static Scalar run(Scalar a, Scalar x) {
969     /*  igamc()
970      *
971      *	Incomplete gamma integral (modified for Eigen)
972      *
973      *
974      *
975      * SYNOPSIS:
976      *
977      * double a, x, y, igamc();
978      *
979      * y = igamc( a, x );
980      *
981      * DESCRIPTION:
982      *
983      * The function is defined by
984      *
985      *
986      *  igamc(a,x)   =   1 - igam(a,x)
987      *
988      *                            inf.
989      *                              -
990      *                     1       | |  -t  a-1
991      *               =   -----     |   e   t   dt.
992      *                    -      | |
993      *                   | (a)    -
994      *                             x
995      *
996      *
997      * In this implementation both arguments must be positive.
998      * The integral is evaluated by either a power series or
999      * continued fraction expansion, depending on the relative
1000      * values of a and x.
1001      *
1002      * ACCURACY (float):
1003      *
1004      *                      Relative error:
1005      * arithmetic   domain     # trials      peak         rms
1006      *    IEEE      0,30        30000       7.8e-6      5.9e-7
1007      *
1008      *
1009      * ACCURACY (double):
1010      *
1011      * Tested at random a, x.
1012      *                a         x                      Relative error:
1013      * arithmetic   domain   domain     # trials      peak         rms
1014      *    IEEE     0.5,100   0,100      200000       1.9e-14     1.7e-15
1015      *    IEEE     0.01,0.5  0,100      200000       1.4e-13     1.6e-15
1016      *
1017      */
1018     /*
1019       Cephes Math Library Release 2.2: June, 1992
1020       Copyright 1985, 1987, 1992 by Stephen L. Moshier
1021       Direct inquiries to 30 Frost Street, Cambridge, MA 02140
1022     */
1023     const Scalar zero = 0;
1024     const Scalar one = 1;
1025     const Scalar nan = NumTraits<Scalar>::quiet_NaN();
1026 
1027     if ((x < zero) || (a <= zero)) {
1028       // domain error
1029       return nan;
1030     }
1031 
1032     if ((numext::isnan)(a) || (numext::isnan)(x)) {  // propagate nans
1033       return nan;
1034     }
1035 
1036     if ((x < one) || (x < a)) {
1037       return (one - igamma_series_impl<Scalar, VALUE>::run(a, x));
1038     }
1039 
1040     return igammac_cf_impl<Scalar, VALUE>::run(a, x);
1041   }
1042 };
1043 
1044 #endif  // EIGEN_HAS_C99_MATH
1045 
1046 /************************************************************************************************
1047  * Implementation of igamma (incomplete gamma integral), based on Cephes but requires C++11/C99 *
1048  ************************************************************************************************/
1049 
1050 #if !EIGEN_HAS_C99_MATH
1051 
1052 template <typename Scalar, IgammaComputationMode mode>
1053 struct igamma_generic_impl {
1054   EIGEN_DEVICE_FUNC
1055   static EIGEN_STRONG_INLINE Scalar run(Scalar a, Scalar x) {
1056     EIGEN_STATIC_ASSERT((internal::is_same<Scalar, Scalar>::value == false),
1057                         THIS_TYPE_IS_NOT_SUPPORTED);
1058     return Scalar(0);
1059   }
1060 };
1061 
1062 #else
1063 
1064 template <typename Scalar, IgammaComputationMode mode>
1065 struct igamma_generic_impl {
1066   EIGEN_DEVICE_FUNC
1067   static Scalar run(Scalar a, Scalar x) {
1068     /* Depending on the mode, returns
1069      * - VALUE: incomplete Gamma function igamma(a, x)
1070      * - DERIVATIVE: derivative of incomplete Gamma function d/da igamma(a, x)
1071      * - SAMPLE_DERIVATIVE: implicit derivative of a Gamma random variable
1072      * x ~ Gamma(x | a, 1), dx/da = -1 / Gamma(x | a, 1) * d igamma(a, x) / dx
1073      *
1074      * Derivatives are implemented by forward-mode differentiation.
1075      */
1076     const Scalar zero = 0;
1077     const Scalar one = 1;
1078     const Scalar nan = NumTraits<Scalar>::quiet_NaN();
1079 
1080     if (x == zero) return zero;
1081 
1082     if ((x < zero) || (a <= zero)) {  // domain error
1083       return nan;
1084     }
1085 
1086     if ((numext::isnan)(a) || (numext::isnan)(x)) {  // propagate nans
1087       return nan;
1088     }
1089 
1090     if ((x > one) && (x > a)) {
1091       Scalar ret = igammac_cf_impl<Scalar, mode>::run(a, x);
1092       if (mode == VALUE) {
1093         return one - ret;
1094       } else {
1095         return -ret;
1096       }
1097     }
1098 
1099     return igamma_series_impl<Scalar, mode>::run(a, x);
1100   }
1101 };
1102 
1103 #endif  // EIGEN_HAS_C99_MATH
1104 
1105 template <typename Scalar>
1106 struct igamma_retval {
1107   typedef Scalar type;
1108 };
1109 
1110 template <typename Scalar>
1111 struct igamma_impl : igamma_generic_impl<Scalar, VALUE> {
1112   /* igam()
1113    * Incomplete gamma integral.
1114    *
1115    * The CDF of Gamma(a, 1) random variable at the point x.
1116    *
1117    * Accuracy estimation. For each a in [10^-2, 10^-1...10^3] we sample
1118    * 50 Gamma random variables x ~ Gamma(x | a, 1), a total of 300 points.
1119    * The ground truth is computed by mpmath. Mean absolute error:
1120    * float: 1.26713e-05
1121    * double: 2.33606e-12
1122    *
1123    * Cephes documentation below.
1124    *
1125    * SYNOPSIS:
1126    *
1127    * double a, x, y, igam();
1128    *
1129    * y = igam( a, x );
1130    *
1131    * DESCRIPTION:
1132    *
1133    * The function is defined by
1134    *
1135    *                           x
1136    *                            -
1137    *                   1       | |  -t  a-1
1138    *  igam(a,x)  =   -----     |   e   t   dt.
1139    *                  -      | |
1140    *                 | (a)    -
1141    *                           0
1142    *
1143    *
1144    * In this implementation both arguments must be positive.
1145    * The integral is evaluated by either a power series or
1146    * continued fraction expansion, depending on the relative
1147    * values of a and x.
1148    *
1149    * ACCURACY (double):
1150    *
1151    *                      Relative error:
1152    * arithmetic   domain     # trials      peak         rms
1153    *    IEEE      0,30       200000       3.6e-14     2.9e-15
1154    *    IEEE      0,100      300000       9.9e-14     1.5e-14
1155    *
1156    *
1157    * ACCURACY (float):
1158    *
1159    *                      Relative error:
1160    * arithmetic   domain     # trials      peak         rms
1161    *    IEEE      0,30        20000       7.8e-6      5.9e-7
1162    *
1163    */
1164   /*
1165     Cephes Math Library Release 2.2: June, 1992
1166     Copyright 1985, 1987, 1992 by Stephen L. Moshier
1167     Direct inquiries to 30 Frost Street, Cambridge, MA 02140
1168   */
1169 
1170   /* left tail of incomplete gamma function:
1171    *
1172    *          inf.      k
1173    *   a  -x   -       x
1174    *  x  e     >   ----------
1175    *           -     -
1176    *          k=0   | (a+k+1)
1177    *
1178    */
1179 };
1180 
1181 template <typename Scalar>
1182 struct igamma_der_a_retval : igamma_retval<Scalar> {};
1183 
1184 template <typename Scalar>
1185 struct igamma_der_a_impl : igamma_generic_impl<Scalar, DERIVATIVE> {
1186   /* Derivative of the incomplete Gamma function with respect to a.
1187    *
1188    * Computes d/da igamma(a, x) by forward differentiation of the igamma code.
1189    *
1190    * Accuracy estimation. For each a in [10^-2, 10^-1...10^3] we sample
1191    * 50 Gamma random variables x ~ Gamma(x | a, 1), a total of 300 points.
1192    * The ground truth is computed by mpmath. Mean absolute error:
1193    * float: 6.17992e-07
1194    * double: 4.60453e-12
1195    *
1196    * Reference:
1197    * R. Moore. "Algorithm AS 187: Derivatives of the incomplete gamma
1198    * integral". Journal of the Royal Statistical Society. 1982
1199    */
1200 };
1201 
1202 template <typename Scalar>
1203 struct gamma_sample_der_alpha_retval : igamma_retval<Scalar> {};
1204 
1205 template <typename Scalar>
1206 struct gamma_sample_der_alpha_impl
1207     : igamma_generic_impl<Scalar, SAMPLE_DERIVATIVE> {
1208   /* Derivative of a Gamma random variable sample with respect to alpha.
1209    *
1210    * Consider a sample of a Gamma random variable with the concentration
1211    * parameter alpha: sample ~ Gamma(alpha, 1). The reparameterization
1212    * derivative that we want to compute is dsample / dalpha =
1213    * d igammainv(alpha, u) / dalpha, where u = igamma(alpha, sample).
1214    * However, this formula is numerically unstable and expensive, so instead
1215    * we use implicit differentiation:
1216    *
1217    * igamma(alpha, sample) = u, where u ~ Uniform(0, 1).
1218    * Apply d / dalpha to both sides:
1219    * d igamma(alpha, sample) / dalpha
1220    *     + d igamma(alpha, sample) / dsample * dsample/dalpha  = 0
1221    * d igamma(alpha, sample) / dalpha
1222    *     + Gamma(sample | alpha, 1) dsample / dalpha = 0
1223    * dsample/dalpha = - (d igamma(alpha, sample) / dalpha)
1224    *                   / Gamma(sample | alpha, 1)
1225    *
1226    * Here Gamma(sample | alpha, 1) is the PDF of the Gamma distribution
1227    * (note that the derivative of the CDF w.r.t. sample is the PDF).
1228    * See the reference below for more details.
1229    *
1230    * The derivative of igamma(alpha, sample) is computed by forward
1231    * differentiation of the igamma code. Division by the Gamma PDF is performed
1232    * in the same code, increasing the accuracy and speed due to cancellation
1233    * of some terms.
1234    *
1235    * Accuracy estimation. For each alpha in [10^-2, 10^-1...10^3] we sample
1236    * 50 Gamma random variables sample ~ Gamma(sample | alpha, 1), a total of 300
1237    * points. The ground truth is computed by mpmath. Mean absolute error:
1238    * float: 2.1686e-06
1239    * double: 1.4774e-12
1240    *
1241    * Reference:
1242    * M. Figurnov, S. Mohamed, A. Mnih "Implicit Reparameterization Gradients".
1243    * 2018
1244    */
1245 };
1246 
1247 /*****************************************************************************
1248  * Implementation of Riemann zeta function of two arguments, based on Cephes *
1249  *****************************************************************************/
1250 
1251 template <typename Scalar>
1252 struct zeta_retval {
1253     typedef Scalar type;
1254 };
1255 
1256 template <typename Scalar>
1257 struct zeta_impl_series {
1258   EIGEN_DEVICE_FUNC
1259   static EIGEN_STRONG_INLINE Scalar run(const Scalar) {
1260     EIGEN_STATIC_ASSERT((internal::is_same<Scalar, Scalar>::value == false),
1261                         THIS_TYPE_IS_NOT_SUPPORTED);
1262     return Scalar(0);
1263   }
1264 };
1265 
1266 template <>
1267 struct zeta_impl_series<float> {
1268   EIGEN_DEVICE_FUNC
1269   static EIGEN_STRONG_INLINE bool run(float& a, float& b, float& s, const float x, const float machep) {
1270     int i = 0;
1271     while(i < 9)
1272     {
1273         i += 1;
1274         a += 1.0f;
1275         b = numext::pow( a, -x );
1276         s += b;
1277         if( numext::abs(b/s) < machep )
1278             return true;
1279     }
1280 
1281     //Return whether we are done
1282     return false;
1283   }
1284 };
1285 
1286 template <>
1287 struct zeta_impl_series<double> {
1288   EIGEN_DEVICE_FUNC
1289   static EIGEN_STRONG_INLINE bool run(double& a, double& b, double& s, const double x, const double machep) {
1290     int i = 0;
1291     while( (i < 9) || (a <= 9.0) )
1292     {
1293         i += 1;
1294         a += 1.0;
1295         b = numext::pow( a, -x );
1296         s += b;
1297         if( numext::abs(b/s) < machep )
1298             return true;
1299     }
1300 
1301     //Return whether we are done
1302     return false;
1303   }
1304 };
1305 
1306 template <typename Scalar>
1307 struct zeta_impl {
1308     EIGEN_DEVICE_FUNC
1309     static Scalar run(Scalar x, Scalar q) {
1310         /*							zeta.c
1311          *
1312          *	Riemann zeta function of two arguments
1313          *
1314          *
1315          *
1316          * SYNOPSIS:
1317          *
1318          * double x, q, y, zeta();
1319          *
1320          * y = zeta( x, q );
1321          *
1322          *
1323          *
1324          * DESCRIPTION:
1325          *
1326          *
1327          *
1328          *                 inf.
1329          *                  -        -x
1330          *   zeta(x,q)  =   >   (k+q)
1331          *                  -
1332          *                 k=0
1333          *
1334          * where x > 1 and q is not a negative integer or zero.
1335          * The Euler-Maclaurin summation formula is used to obtain
1336          * the expansion
1337          *
1338          *                n
1339          *                -       -x
1340          * zeta(x,q)  =   >  (k+q)
1341          *                -
1342          *               k=1
1343          *
1344          *           1-x                 inf.  B   x(x+1)...(x+2j)
1345          *      (n+q)           1         -     2j
1346          *  +  ---------  -  -------  +   >    --------------------
1347          *        x-1              x      -                   x+2j+1
1348          *                   2(n+q)      j=1       (2j)! (n+q)
1349          *
1350          * where the B2j are Bernoulli numbers.  Note that (see zetac.c)
1351          * zeta(x,1) = zetac(x) + 1.
1352          *
1353          *
1354          *
1355          * ACCURACY:
1356          *
1357          * Relative error for single precision:
1358          * arithmetic   domain     # trials      peak         rms
1359          *    IEEE      0,25        10000       6.9e-7      1.0e-7
1360          *
1361          * Large arguments may produce underflow in powf(), in which
1362          * case the results are inaccurate.
1363          *
1364          * REFERENCE:
1365          *
1366          * Gradshteyn, I. S., and I. M. Ryzhik, Tables of Integrals,
1367          * Series, and Products, p. 1073; Academic Press, 1980.
1368          *
1369          */
1370 
1371         int i;
1372         Scalar p, r, a, b, k, s, t, w;
1373 
1374         const Scalar A[] = {
1375             Scalar(12.0),
1376             Scalar(-720.0),
1377             Scalar(30240.0),
1378             Scalar(-1209600.0),
1379             Scalar(47900160.0),
1380             Scalar(-1.8924375803183791606e9), /*1.307674368e12/691*/
1381             Scalar(7.47242496e10),
1382             Scalar(-2.950130727918164224e12), /*1.067062284288e16/3617*/
1383             Scalar(1.1646782814350067249e14), /*5.109094217170944e18/43867*/
1384             Scalar(-4.5979787224074726105e15), /*8.028576626982912e20/174611*/
1385             Scalar(1.8152105401943546773e17), /*1.5511210043330985984e23/854513*/
1386             Scalar(-7.1661652561756670113e18) /*1.6938241367317436694528e27/236364091*/
1387             };
1388 
1389         const Scalar maxnum = NumTraits<Scalar>::infinity();
1390         const Scalar zero = 0.0, half = 0.5, one = 1.0;
1391         const Scalar machep = cephes_helper<Scalar>::machep();
1392         const Scalar nan = NumTraits<Scalar>::quiet_NaN();
1393 
1394         if( x == one )
1395             return maxnum;
1396 
1397         if( x < one )
1398         {
1399             return nan;
1400         }
1401 
1402         if( q <= zero )
1403         {
1404             if(q == numext::floor(q))
1405             {
1406                 if (x == numext::floor(x) && long(x) % 2 == 0) {
1407                     return maxnum;
1408                 }
1409                 else {
1410                     return nan;
1411                 }
1412             }
1413             p = x;
1414             r = numext::floor(p);
1415             if (p != r)
1416                 return nan;
1417         }
1418 
1419         /* Permit negative q but continue sum until n+q > +9 .
1420          * This case should be handled by a reflection formula.
1421          * If q<0 and x is an integer, there is a relation to
1422          * the polygamma function.
1423          */
1424         s = numext::pow( q, -x );
1425         a = q;
1426         b = zero;
1427         // Run the summation in a helper function that is specific to the floating precision
1428         if (zeta_impl_series<Scalar>::run(a, b, s, x, machep)) {
1429             return s;
1430         }
1431 
1432         w = a;
1433         s += b*w/(x-one);
1434         s -= half * b;
1435         a = one;
1436         k = zero;
1437         for( i=0; i<12; i++ )
1438         {
1439             a *= x + k;
1440             b /= w;
1441             t = a*b/A[i];
1442             s = s + t;
1443             t = numext::abs(t/s);
1444             if( t < machep ) {
1445               break;
1446             }
1447             k += one;
1448             a *= x + k;
1449             b /= w;
1450             k += one;
1451         }
1452         return s;
1453   }
1454 };
1455 
1456 /****************************************************************************
1457  * Implementation of polygamma function, requires C++11/C99                 *
1458  ****************************************************************************/
1459 
1460 template <typename Scalar>
1461 struct polygamma_retval {
1462     typedef Scalar type;
1463 };
1464 
1465 #if !EIGEN_HAS_C99_MATH
1466 
1467 template <typename Scalar>
1468 struct polygamma_impl {
1469     EIGEN_DEVICE_FUNC
1470     static EIGEN_STRONG_INLINE Scalar run(Scalar n, Scalar x) {
1471         EIGEN_STATIC_ASSERT((internal::is_same<Scalar, Scalar>::value == false),
1472                             THIS_TYPE_IS_NOT_SUPPORTED);
1473         return Scalar(0);
1474     }
1475 };
1476 
1477 #else
1478 
1479 template <typename Scalar>
1480 struct polygamma_impl {
1481     EIGEN_DEVICE_FUNC
1482     static Scalar run(Scalar n, Scalar x) {
1483         Scalar zero = 0.0, one = 1.0;
1484         Scalar nplus = n + one;
1485         const Scalar nan = NumTraits<Scalar>::quiet_NaN();
1486 
1487         // Check that n is a non-negative integer
1488         if (numext::floor(n) != n || n < zero) {
1489             return nan;
1490         }
1491         // Just return the digamma function for n = 0
1492         else if (n == zero) {
1493             return digamma_impl<Scalar>::run(x);
1494         }
1495         // Use the same implementation as scipy
1496         else {
1497             Scalar factorial = numext::exp(lgamma_impl<Scalar>::run(nplus));
1498             return numext::pow(-one, nplus) * factorial * zeta_impl<Scalar>::run(nplus, x);
1499         }
1500   }
1501 };
1502 
1503 #endif  // EIGEN_HAS_C99_MATH
1504 
1505 /************************************************************************************************
1506  * Implementation of betainc (incomplete beta integral), based on Cephes but requires C++11/C99 *
1507  ************************************************************************************************/
1508 
1509 template <typename Scalar>
1510 struct betainc_retval {
1511   typedef Scalar type;
1512 };
1513 
1514 #if !EIGEN_HAS_C99_MATH
1515 
1516 template <typename Scalar>
1517 struct betainc_impl {
1518   EIGEN_DEVICE_FUNC
1519   static EIGEN_STRONG_INLINE Scalar run(Scalar a, Scalar b, Scalar x) {
1520     EIGEN_STATIC_ASSERT((internal::is_same<Scalar, Scalar>::value == false),
1521                         THIS_TYPE_IS_NOT_SUPPORTED);
1522     return Scalar(0);
1523   }
1524 };
1525 
1526 #else
1527 
1528 template <typename Scalar>
1529 struct betainc_impl {
1530   EIGEN_DEVICE_FUNC
1531   static EIGEN_STRONG_INLINE Scalar run(Scalar, Scalar, Scalar) {
1532     /*	betaincf.c
1533      *
1534      *	Incomplete beta integral
1535      *
1536      *
1537      * SYNOPSIS:
1538      *
1539      * float a, b, x, y, betaincf();
1540      *
1541      * y = betaincf( a, b, x );
1542      *
1543      *
1544      * DESCRIPTION:
1545      *
1546      * Returns incomplete beta integral of the arguments, evaluated
1547      * from zero to x.  The function is defined as
1548      *
1549      *                  x
1550      *     -            -
1551      *    | (a+b)      | |  a-1     b-1
1552      *  -----------    |   t   (1-t)   dt.
1553      *   -     -     | |
1554      *  | (a) | (b)   -
1555      *                 0
1556      *
1557      * The domain of definition is 0 <= x <= 1.  In this
1558      * implementation a and b are restricted to positive values.
1559      * The integral from x to 1 may be obtained by the symmetry
1560      * relation
1561      *
1562      *    1 - betainc( a, b, x )  =  betainc( b, a, 1-x ).
1563      *
1564      * The integral is evaluated by a continued fraction expansion.
1565      * If a < 1, the function calls itself recursively after a
1566      * transformation to increase a to a+1.
1567      *
1568      * ACCURACY (float):
1569      *
1570      * Tested at random points (a,b,x) with a and b in the indicated
1571      * interval and x between 0 and 1.
1572      *
1573      * arithmetic   domain     # trials      peak         rms
1574      * Relative error:
1575      *    IEEE       0,30       10000       3.7e-5      5.1e-6
1576      *    IEEE       0,100      10000       1.7e-4      2.5e-5
1577      * The useful domain for relative error is limited by underflow
1578      * of the single precision exponential function.
1579      * Absolute error:
1580      *    IEEE       0,30      100000       2.2e-5      9.6e-7
1581      *    IEEE       0,100      10000       6.5e-5      3.7e-6
1582      *
1583      * Larger errors may occur for extreme ratios of a and b.
1584      *
1585      * ACCURACY (double):
1586      * arithmetic   domain     # trials      peak         rms
1587      *    IEEE      0,5         10000       6.9e-15     4.5e-16
1588      *    IEEE      0,85       250000       2.2e-13     1.7e-14
1589      *    IEEE      0,1000      30000       5.3e-12     6.3e-13
1590      *    IEEE      0,10000    250000       9.3e-11     7.1e-12
1591      *    IEEE      0,100000    10000       8.7e-10     4.8e-11
1592      * Outputs smaller than the IEEE gradual underflow threshold
1593      * were excluded from these statistics.
1594      *
1595      * ERROR MESSAGES:
1596      *   message         condition      value returned
1597      * incbet domain      x<0, x>1          nan
1598      * incbet underflow                     nan
1599      */
1600 
1601     EIGEN_STATIC_ASSERT((internal::is_same<Scalar, Scalar>::value == false),
1602                         THIS_TYPE_IS_NOT_SUPPORTED);
1603     return Scalar(0);
1604   }
1605 };
1606 
1607 /* Continued fraction expansion #1 for incomplete beta integral (small_branch = True)
1608  * Continued fraction expansion #2 for incomplete beta integral (small_branch = False)
1609  */
1610 template <typename Scalar>
1611 struct incbeta_cfe {
1612   EIGEN_DEVICE_FUNC
1613   static EIGEN_STRONG_INLINE Scalar run(Scalar a, Scalar b, Scalar x, bool small_branch) {
1614     EIGEN_STATIC_ASSERT((internal::is_same<Scalar, float>::value ||
1615                          internal::is_same<Scalar, double>::value),
1616                         THIS_TYPE_IS_NOT_SUPPORTED);
1617     const Scalar big = cephes_helper<Scalar>::big();
1618     const Scalar machep = cephes_helper<Scalar>::machep();
1619     const Scalar biginv = cephes_helper<Scalar>::biginv();
1620 
1621     const Scalar zero = 0;
1622     const Scalar one = 1;
1623     const Scalar two = 2;
1624 
1625     Scalar xk, pk, pkm1, pkm2, qk, qkm1, qkm2;
1626     Scalar k1, k2, k3, k4, k5, k6, k7, k8, k26update;
1627     Scalar ans;
1628     int n;
1629 
1630     const int num_iters = (internal::is_same<Scalar, float>::value) ? 100 : 300;
1631     const Scalar thresh =
1632         (internal::is_same<Scalar, float>::value) ? machep : Scalar(3) * machep;
1633     Scalar r = (internal::is_same<Scalar, float>::value) ? zero : one;
1634 
1635     if (small_branch) {
1636       k1 = a;
1637       k2 = a + b;
1638       k3 = a;
1639       k4 = a + one;
1640       k5 = one;
1641       k6 = b - one;
1642       k7 = k4;
1643       k8 = a + two;
1644       k26update = one;
1645     } else {
1646       k1 = a;
1647       k2 = b - one;
1648       k3 = a;
1649       k4 = a + one;
1650       k5 = one;
1651       k6 = a + b;
1652       k7 = a + one;
1653       k8 = a + two;
1654       k26update = -one;
1655       x = x / (one - x);
1656     }
1657 
1658     pkm2 = zero;
1659     qkm2 = one;
1660     pkm1 = one;
1661     qkm1 = one;
1662     ans = one;
1663     n = 0;
1664 
1665     do {
1666       xk = -(x * k1 * k2) / (k3 * k4);
1667       pk = pkm1 + pkm2 * xk;
1668       qk = qkm1 + qkm2 * xk;
1669       pkm2 = pkm1;
1670       pkm1 = pk;
1671       qkm2 = qkm1;
1672       qkm1 = qk;
1673 
1674       xk = (x * k5 * k6) / (k7 * k8);
1675       pk = pkm1 + pkm2 * xk;
1676       qk = qkm1 + qkm2 * xk;
1677       pkm2 = pkm1;
1678       pkm1 = pk;
1679       qkm2 = qkm1;
1680       qkm1 = qk;
1681 
1682       if (qk != zero) {
1683         r = pk / qk;
1684         if (numext::abs(ans - r) < numext::abs(r) * thresh) {
1685           return r;
1686         }
1687         ans = r;
1688       }
1689 
1690       k1 += one;
1691       k2 += k26update;
1692       k3 += two;
1693       k4 += two;
1694       k5 += one;
1695       k6 -= k26update;
1696       k7 += two;
1697       k8 += two;
1698 
1699       if ((numext::abs(qk) + numext::abs(pk)) > big) {
1700         pkm2 *= biginv;
1701         pkm1 *= biginv;
1702         qkm2 *= biginv;
1703         qkm1 *= biginv;
1704       }
1705       if ((numext::abs(qk) < biginv) || (numext::abs(pk) < biginv)) {
1706         pkm2 *= big;
1707         pkm1 *= big;
1708         qkm2 *= big;
1709         qkm1 *= big;
1710       }
1711     } while (++n < num_iters);
1712 
1713     return ans;
1714   }
1715 };
1716 
1717 /* Helper functions depending on the Scalar type */
1718 template <typename Scalar>
1719 struct betainc_helper {};
1720 
1721 template <>
1722 struct betainc_helper<float> {
1723   /* Core implementation, assumes a large (> 1.0) */
1724   EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE float incbsa(float aa, float bb,
1725                                                             float xx) {
1726     float ans, a, b, t, x, onemx;
1727     bool reversed_a_b = false;
1728 
1729     onemx = 1.0f - xx;
1730 
1731     /* see if x is greater than the mean */
1732     if (xx > (aa / (aa + bb))) {
1733       reversed_a_b = true;
1734       a = bb;
1735       b = aa;
1736       t = xx;
1737       x = onemx;
1738     } else {
1739       a = aa;
1740       b = bb;
1741       t = onemx;
1742       x = xx;
1743     }
1744 
1745     /* Choose expansion for optimal convergence */
1746     if (b > 10.0f) {
1747       if (numext::abs(b * x / a) < 0.3f) {
1748         t = betainc_helper<float>::incbps(a, b, x);
1749         if (reversed_a_b) t = 1.0f - t;
1750         return t;
1751       }
1752     }
1753 
1754     ans = x * (a + b - 2.0f) / (a - 1.0f);
1755     if (ans < 1.0f) {
1756       ans = incbeta_cfe<float>::run(a, b, x, true /* small_branch */);
1757       t = b * numext::log(t);
1758     } else {
1759       ans = incbeta_cfe<float>::run(a, b, x, false /* small_branch */);
1760       t = (b - 1.0f) * numext::log(t);
1761     }
1762 
1763     t += a * numext::log(x) + lgamma_impl<float>::run(a + b) -
1764          lgamma_impl<float>::run(a) - lgamma_impl<float>::run(b);
1765     t += numext::log(ans / a);
1766     t = numext::exp(t);
1767 
1768     if (reversed_a_b) t = 1.0f - t;
1769     return t;
1770   }
1771 
1772   EIGEN_DEVICE_FUNC
1773   static EIGEN_STRONG_INLINE float incbps(float a, float b, float x) {
1774     float t, u, y, s;
1775     const float machep = cephes_helper<float>::machep();
1776 
1777     y = a * numext::log(x) + (b - 1.0f) * numext::log1p(-x) - numext::log(a);
1778     y -= lgamma_impl<float>::run(a) + lgamma_impl<float>::run(b);
1779     y += lgamma_impl<float>::run(a + b);
1780 
1781     t = x / (1.0f - x);
1782     s = 0.0f;
1783     u = 1.0f;
1784     do {
1785       b -= 1.0f;
1786       if (b == 0.0f) {
1787         break;
1788       }
1789       a += 1.0f;
1790       u *= t * b / a;
1791       s += u;
1792     } while (numext::abs(u) > machep);
1793 
1794     return numext::exp(y) * (1.0f + s);
1795   }
1796 };
1797 
1798 template <>
1799 struct betainc_impl<float> {
1800   EIGEN_DEVICE_FUNC
1801   static float run(float a, float b, float x) {
1802     const float nan = NumTraits<float>::quiet_NaN();
1803     float ans, t;
1804 
1805     if (a <= 0.0f) return nan;
1806     if (b <= 0.0f) return nan;
1807     if ((x <= 0.0f) || (x >= 1.0f)) {
1808       if (x == 0.0f) return 0.0f;
1809       if (x == 1.0f) return 1.0f;
1810       // mtherr("betaincf", DOMAIN);
1811       return nan;
1812     }
1813 
1814     /* transformation for small aa */
1815     if (a <= 1.0f) {
1816       ans = betainc_helper<float>::incbsa(a + 1.0f, b, x);
1817       t = a * numext::log(x) + b * numext::log1p(-x) +
1818           lgamma_impl<float>::run(a + b) - lgamma_impl<float>::run(a + 1.0f) -
1819           lgamma_impl<float>::run(b);
1820       return (ans + numext::exp(t));
1821     } else {
1822       return betainc_helper<float>::incbsa(a, b, x);
1823     }
1824   }
1825 };
1826 
1827 template <>
1828 struct betainc_helper<double> {
1829   EIGEN_DEVICE_FUNC
1830   static EIGEN_STRONG_INLINE double incbps(double a, double b, double x) {
1831     const double machep = cephes_helper<double>::machep();
1832 
1833     double s, t, u, v, n, t1, z, ai;
1834 
1835     ai = 1.0 / a;
1836     u = (1.0 - b) * x;
1837     v = u / (a + 1.0);
1838     t1 = v;
1839     t = u;
1840     n = 2.0;
1841     s = 0.0;
1842     z = machep * ai;
1843     while (numext::abs(v) > z) {
1844       u = (n - b) * x / n;
1845       t *= u;
1846       v = t / (a + n);
1847       s += v;
1848       n += 1.0;
1849     }
1850     s += t1;
1851     s += ai;
1852 
1853     u = a * numext::log(x);
1854     // TODO: gamma() is not directly implemented in Eigen.
1855     /*
1856     if ((a + b) < maxgam && numext::abs(u) < maxlog) {
1857       t = gamma(a + b) / (gamma(a) * gamma(b));
1858       s = s * t * pow(x, a);
1859     }
1860     */
1861     t = lgamma_impl<double>::run(a + b) - lgamma_impl<double>::run(a) -
1862         lgamma_impl<double>::run(b) + u + numext::log(s);
1863     return s = numext::exp(t);
1864   }
1865 };
1866 
1867 template <>
1868 struct betainc_impl<double> {
1869   EIGEN_DEVICE_FUNC
1870   static double run(double aa, double bb, double xx) {
1871     const double nan = NumTraits<double>::quiet_NaN();
1872     const double machep = cephes_helper<double>::machep();
1873     // const double maxgam = 171.624376956302725;
1874 
1875     double a, b, t, x, xc, w, y;
1876     bool reversed_a_b = false;
1877 
1878     if (aa <= 0.0 || bb <= 0.0) {
1879       return nan;  // goto domerr;
1880     }
1881 
1882     if ((xx <= 0.0) || (xx >= 1.0)) {
1883       if (xx == 0.0) return (0.0);
1884       if (xx == 1.0) return (1.0);
1885       // mtherr("incbet", DOMAIN);
1886       return nan;
1887     }
1888 
1889     if ((bb * xx) <= 1.0 && xx <= 0.95) {
1890       return betainc_helper<double>::incbps(aa, bb, xx);
1891     }
1892 
1893     w = 1.0 - xx;
1894 
1895     /* Reverse a and b if x is greater than the mean. */
1896     if (xx > (aa / (aa + bb))) {
1897       reversed_a_b = true;
1898       a = bb;
1899       b = aa;
1900       xc = xx;
1901       x = w;
1902     } else {
1903       a = aa;
1904       b = bb;
1905       xc = w;
1906       x = xx;
1907     }
1908 
1909     if (reversed_a_b && (b * x) <= 1.0 && x <= 0.95) {
1910       t = betainc_helper<double>::incbps(a, b, x);
1911       if (t <= machep) {
1912         t = 1.0 - machep;
1913       } else {
1914         t = 1.0 - t;
1915       }
1916       return t;
1917     }
1918 
1919     /* Choose expansion for better convergence. */
1920     y = x * (a + b - 2.0) - (a - 1.0);
1921     if (y < 0.0) {
1922       w = incbeta_cfe<double>::run(a, b, x, true /* small_branch */);
1923     } else {
1924       w = incbeta_cfe<double>::run(a, b, x, false /* small_branch */) / xc;
1925     }
1926 
1927     /* Multiply w by the factor
1928          a      b   _             _     _
1929         x  (1-x)   | (a+b) / ( a | (a) | (b) ) .   */
1930 
1931     y = a * numext::log(x);
1932     t = b * numext::log(xc);
1933     // TODO: gamma is not directly implemented in Eigen.
1934     /*
1935     if ((a + b) < maxgam && numext::abs(y) < maxlog && numext::abs(t) < maxlog)
1936     {
1937       t = pow(xc, b);
1938       t *= pow(x, a);
1939       t /= a;
1940       t *= w;
1941       t *= gamma(a + b) / (gamma(a) * gamma(b));
1942     } else {
1943     */
1944     /* Resort to logarithms.  */
1945     y += t + lgamma_impl<double>::run(a + b) - lgamma_impl<double>::run(a) -
1946          lgamma_impl<double>::run(b);
1947     y += numext::log(w / a);
1948     t = numext::exp(y);
1949 
1950     /* } */
1951     // done:
1952 
1953     if (reversed_a_b) {
1954       if (t <= machep) {
1955         t = 1.0 - machep;
1956       } else {
1957         t = 1.0 - t;
1958       }
1959     }
1960     return t;
1961   }
1962 };
1963 
1964 #endif  // EIGEN_HAS_C99_MATH
1965 
1966 }  // end namespace internal
1967 
1968 namespace numext {
1969 
1970 template <typename Scalar>
1971 EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(lgamma, Scalar)
1972     lgamma(const Scalar& x) {
1973   return EIGEN_MATHFUNC_IMPL(lgamma, Scalar)::run(x);
1974 }
1975 
1976 template <typename Scalar>
1977 EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(digamma, Scalar)
1978     digamma(const Scalar& x) {
1979   return EIGEN_MATHFUNC_IMPL(digamma, Scalar)::run(x);
1980 }
1981 
1982 template <typename Scalar>
1983 EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(zeta, Scalar)
1984 zeta(const Scalar& x, const Scalar& q) {
1985     return EIGEN_MATHFUNC_IMPL(zeta, Scalar)::run(x, q);
1986 }
1987 
1988 template <typename Scalar>
1989 EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(polygamma, Scalar)
1990 polygamma(const Scalar& n, const Scalar& x) {
1991     return EIGEN_MATHFUNC_IMPL(polygamma, Scalar)::run(n, x);
1992 }
1993 
1994 template <typename Scalar>
1995 EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(erf, Scalar)
1996     erf(const Scalar& x) {
1997   return EIGEN_MATHFUNC_IMPL(erf, Scalar)::run(x);
1998 }
1999 
2000 template <typename Scalar>
2001 EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(erfc, Scalar)
2002     erfc(const Scalar& x) {
2003   return EIGEN_MATHFUNC_IMPL(erfc, Scalar)::run(x);
2004 }
2005 
2006 template <typename Scalar>
2007 EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(ndtri, Scalar)
2008     ndtri(const Scalar& x) {
2009   return EIGEN_MATHFUNC_IMPL(ndtri, Scalar)::run(x);
2010 }
2011 
2012 template <typename Scalar>
2013 EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(igamma, Scalar)
2014     igamma(const Scalar& a, const Scalar& x) {
2015   return EIGEN_MATHFUNC_IMPL(igamma, Scalar)::run(a, x);
2016 }
2017 
2018 template <typename Scalar>
2019 EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(igamma_der_a, Scalar)
2020     igamma_der_a(const Scalar& a, const Scalar& x) {
2021   return EIGEN_MATHFUNC_IMPL(igamma_der_a, Scalar)::run(a, x);
2022 }
2023 
2024 template <typename Scalar>
2025 EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(gamma_sample_der_alpha, Scalar)
2026     gamma_sample_der_alpha(const Scalar& a, const Scalar& x) {
2027   return EIGEN_MATHFUNC_IMPL(gamma_sample_der_alpha, Scalar)::run(a, x);
2028 }
2029 
2030 template <typename Scalar>
2031 EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(igammac, Scalar)
2032     igammac(const Scalar& a, const Scalar& x) {
2033   return EIGEN_MATHFUNC_IMPL(igammac, Scalar)::run(a, x);
2034 }
2035 
2036 template <typename Scalar>
2037 EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(betainc, Scalar)
2038     betainc(const Scalar& a, const Scalar& b, const Scalar& x) {
2039   return EIGEN_MATHFUNC_IMPL(betainc, Scalar)::run(a, b, x);
2040 }
2041 
2042 }  // end namespace numext
2043 }  // end namespace Eigen
2044 
2045 #endif  // EIGEN_SPECIAL_FUNCTIONS_H
2046