1 //                                               -*- C++ -*-
2 /**
3  *  @brief OpenTURNS wrapper to a library of special functions
4  *
5  *  Copyright 2005-2021 Airbus-EDF-IMACS-ONERA-Phimeca
6  *
7  *  This library is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU Lesser General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public License
18  *  along with this library.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 #include <cmath>
22 #include <limits>
23 #include <cstdlib>
24 #include <iostream>
25 
26 #include "openturns/SpecFunc.hxx"
27 #include "openturns/BetaFunctions.hxx"
28 #include "openturns/ExponentialIntegralFunctions.hxx"
29 #include "openturns/Debye.hxx"
30 #include "Faddeeva.hh"
31 #include "openturns/GammaFunctions.hxx"
32 #include "openturns/Exception.hxx"
33 #include "openturns/ResourceMap.hxx"
34 #include "openturns/Function.hxx"
35 #include "openturns/GaussKronrod.hxx"
36 #include "openturns/PlatformInfo.hxx"
37 
38 #ifdef OPENTURNS_HAVE_BOOST
39 
40 #include <boost/math/special_functions/bessel.hpp>
41 #include <boost/version.hpp>
42 
43 #ifdef OPENTURNS_HAVE_MPC
44 #include <boost/multiprecision/mpc.hpp>
45 #endif
46 
47 #ifdef OPENTURNS_HAVE_MPFR
48 #include <boost/multiprecision/mpfr.hpp>
49 #endif
50 
51 #if (BOOST_VERSION >= 105600)
52 
53 #include <boost/math/special_functions/bessel_prime.hpp>
54 
55 #endif
56 
57 #else
58 
59 #include "openturns/GaussKronrod.hxx"
60 #include "openturns/SymbolicFunction.hxx"
61 #include "openturns/Interval.hxx"
62 
63 #endif
64 
65 BEGIN_NAMESPACE_OPENTURNS
66 
67 // 0.39894228040143267 = 1 / sqrt(2.pi)
68 const Scalar SpecFunc::ISQRT2PI              = 0.3989422804014326779399462;
69 // 2.5066282746310005024 = sqrt(2.pi)
70 const Scalar SpecFunc::SQRT2PI               = 2.506628274631000502415765;
71 // 0.91893853320467274177 = log(sqrt(2.pi))
72 const Scalar SpecFunc::LOGSQRT2PI            = 0.91893853320467274178;
73 // 0.57721566490153286 = Euler constant gamma
74 const Scalar SpecFunc::EulerConstant         = 0.57721566490153286;
75 // 1.64493406684822643 = pi^2 / 6
76 const Scalar SpecFunc::PI2_6                 = 1.64493406684822643;
77 // 1.28254983016118640 = pi / sqrt(6)
78 const Scalar SpecFunc::PI_SQRT6              = 1.28254983016118640;
79 // 0.45005320754569466 = gamma * sqrt(6) / pi
80 const Scalar SpecFunc::EULERSQRT6_PI         = 0.45005320754569466;
81 // 3.28986813369645287 = pi^2 / 3
82 const Scalar SpecFunc::PI2_3                 = 3.28986813369645287;
83 // 0.55132889542179204 = sqrt(3) / pi
84 const Scalar SpecFunc::SQRT3_PI              = 0.55132889542179204;
85 // 1.81379936423421785 = pi / sqrt(3)
86 const Scalar SpecFunc::PI_SQRT3              = 1.81379936423421785;
87 // 6.283185307179586476925286 = 2*pi
88 const Scalar SpecFunc::TWOPI                 = 6.283185307179586476925286;
89 // 1.20205690315959429 = Zeta(3)
90 const Scalar SpecFunc::ZETA3                 = 1.20205690315959429;
91 // Scalar limits
92 const Scalar SpecFunc::MinScalar     = std::numeric_limits<Scalar>::min();
93 const Scalar SpecFunc::LogMinScalar  = std::log(MinScalar);
94 const Scalar SpecFunc::MaxScalar     = std::numeric_limits<Scalar>::max();
95 const Scalar SpecFunc::LogMaxScalar  = std::log(MaxScalar);
96 const Scalar SpecFunc::LowestScalar  = -MaxScalar;
97 const Scalar SpecFunc::ScalarEpsilon = std::numeric_limits<Scalar>::epsilon();
98 // Maximum number of iterations for the algorithms
99 const UnsignedInteger SpecFunc::MaximumIteration = ResourceMap::GetAsUnsignedInteger("SpecFunc-MaximumIteration");
100 const Scalar SpecFunc::Precision = ResourceMap::GetAsScalar("SpecFunc-Precision");
101 
102 // Information about capabilities
IsBoostAvailable()103 Bool SpecFunc::IsBoostAvailable()
104 {
105 #ifdef OPENTURNS_HAVE_BOOST
106   return true;
107 #else
108   return false;
109 #endif
110 }
111 
IsMPFRAvailable()112 Bool SpecFunc::IsMPFRAvailable()
113 {
114 #ifdef OPENTURNS_HAVE_MPFR
115   return true;
116 #else
117   return false;
118 #endif
119 }
120 
IsMPCAvailable()121 Bool SpecFunc::IsMPCAvailable()
122 {
123 #ifdef OPENTURNS_HAVE_MPC
124   return true;
125 #else
126   return false;
127 #endif
128 }
129 
130 // Some facilities for NaN and inf
IsNaN(const Scalar value)131 Bool SpecFunc::IsNaN(const Scalar value)
132 {
133   return value != value;
134 }
135 
IsInf(const Scalar value)136 Bool SpecFunc::IsInf(const Scalar value)
137 {
138   return (value == value) && IsNaN(value - value);
139 }
140 
IsNormal(const Scalar value)141 Bool SpecFunc::IsNormal(const Scalar value)
142 {
143   return value - value == 0.0;
144 }
145 
146 // Modified first kind Bessel function of order 0: BesselI0(x) = \sum_{m=0}\infty\frac{1}{m!^2}\left(\frac{x}{2}\right)^{2m}
SmallCaseBesselI0(const Scalar x)147 Scalar SpecFunc::SmallCaseBesselI0(const Scalar x)
148 {
149   const Scalar x2 = x * x;
150   Scalar value = 1.0;
151   Scalar r = 1.0;
152   UnsignedInteger k = 1;
153   while ((std::abs(r / value) > 0.0) && (k < SpecFunc::MaximumIteration))
154   {
155     r *= 0.25 * x2 / (k * k);
156     value += r;
157     ++k;
158   }
159   return value;
160 }
161 
LargeCaseLogBesselI0(const Scalar x)162 Scalar SpecFunc::LargeCaseLogBesselI0(const Scalar x)
163 {
164   static Scalar A[12] = {0.125, 7.03125e-02,
165                          7.32421875e-02, 1.1215209960938e-01,
166                          2.2710800170898e-01, 5.7250142097473e-01,
167                          1.7277275025845, 6.0740420012735,
168                          2.4380529699556e+01, 1.1001714026925e+02,
169                          5.5133589612202e+02, 3.0380905109224e+03
170                         };
171   const Scalar ax = std::abs(x);
172   UnsignedInteger k0 = 12;
173   if (ax >= 35.0) k0 = 9;
174   if (ax >= 50.0) k0 = 7;
175   Scalar value = 1.0;
176   const Scalar xR = 1.0 / ax;
177   Scalar xRPow = xR;
178   for (UnsignedInteger k = 0; k < k0; ++k)
179   {
180     value += A[k] * xRPow;
181     xRPow *= xR;
182   }
183   value = std::log(value) + ax - 0.5 * std::log(2.0 * M_PI * ax);
184   return value;
185 }
186 
BesselI0(const Scalar x)187 Scalar SpecFunc::BesselI0(const Scalar x)
188 {
189   if (x == 0.0) return 1.0;
190   // Small argument
191   if (std::abs(x) <= 23.5) return SmallCaseBesselI0(x);
192   // Large argument
193   else return std::exp(LargeCaseLogBesselI0(x));
194 }
195 
LogBesselI0(const Scalar x)196 Scalar SpecFunc::LogBesselI0(const Scalar x)
197 {
198   if (x == 0.0) return 0.0;
199   // Small argument
200   if (std::abs(x) <= 23.5) return std::log(SmallCaseBesselI0(x));
201   // Large argument
202   else return LargeCaseLogBesselI0(x);
203 }
204 
205 // Modified first kind Bessel function of order 1: BesselI1(x) = \sum_{m=0}\infty\frac{1}{m!(m+1)!}\left(\frac{x}{2}\right)^{2m+1}
SmallCaseBesselI1(const Scalar x)206 Scalar SpecFunc::SmallCaseBesselI1(const Scalar x)
207 {
208   const Scalar x2 = x * x;
209   Scalar value = 1.0;
210   Scalar r = 1.0;
211   UnsignedInteger k = 1;
212   while ((std::abs(r / value) > 0.0) && (k < SpecFunc::MaximumIteration))
213   {
214     r *= 0.25 * x2 / (k * (k + 1));
215     value += r;
216     ++k;
217   }
218   value *= 0.5 * x;
219   return value;
220 }
221 
LargeCaseLogBesselI1(const Scalar x)222 Scalar SpecFunc::LargeCaseLogBesselI1(const Scalar x)
223 {
224   static Scalar B[12] = { -0.375, -1.171875e-01,
225                           -1.025390625e-01, -1.4419555664063e-01,
226                           -2.7757644653320e-01, -6.7659258842468e-01,
227                           -1.9935317337513, -6.8839142681099,
228                           -2.7248827311269e+01, -1.2159789187654e+02,
229                           -6.0384407670507e+02, -3.3022722944809e+03
230                         };
231   const Scalar ax = std::abs(x);
232   UnsignedInteger k0 = 12;
233   if (ax >= 35.0) k0 = 9;
234   if (ax >= 50.0) k0 = 7;
235   Scalar value = 1.0;
236   const Scalar xR = 1.0 / ax;
237   Scalar xRPow = xR;
238   for (UnsignedInteger k = 0; k < k0; ++k)
239   {
240     value += B[k] * xRPow;
241     xRPow *= xR;
242   }
243   value = std::log(value) + ax - 0.5 * std::log(2.0 * M_PI * ax);
244   return value;
245 }
246 
BesselI1(const Scalar x)247 Scalar SpecFunc::BesselI1(const Scalar x)
248 {
249   if (x == 0.0) return 0.0;
250   // Small argument
251   if (std::abs(x) <= 22.0) return SmallCaseBesselI1(x);
252   else
253   {
254     const Scalar signX = x <= 0.0 ? -1.0 : 1.0;
255     const Scalar value = signX * std::exp(LargeCaseLogBesselI1(x));
256     return value;
257   }
258 }
259 
LogBesselI1(const Scalar x)260 Scalar SpecFunc::LogBesselI1(const Scalar x)
261 {
262   if (x <= 0.0) return LowestScalar;
263   // Small argument
264   if (std::abs(x) <= 22.0) return std::log(SmallCaseBesselI1(x));
265   else return LargeCaseLogBesselI1(x);
266 }
267 
268 // Difference between the logarithms of BesselI1 and BesselI0:
269 // DeltaLogBesselI10(x) = log(BesselI1(x)) - log(BesselI0(x))
LargeCaseDeltaLogBesselI10(const Scalar x)270 Scalar SpecFunc::LargeCaseDeltaLogBesselI10(const Scalar x)
271 {
272   static Scalar A[12] = {0.125, 7.03125e-02,
273                          7.32421875e-02, 1.1215209960938e-01,
274                          2.2710800170898e-01, 5.7250142097473e-01,
275                          1.7277275025845, 6.0740420012735,
276                          2.4380529699556e+01, 1.1001714026925e+02,
277                          5.5133589612202e+02, 3.0380905109224e+03
278                         };
279   static Scalar B[12] = { -0.375, -1.171875e-01,
280                           -1.025390625e-01, -1.4419555664063e-01,
281                           -2.7757644653320e-01, -6.7659258842468e-01,
282                           -1.9935317337513, -6.8839142681099,
283                           -2.7248827311269e+01, -1.2159789187654e+02,
284                           -6.0384407670507e+02, -3.3022722944809e+03
285                         };
286   const Scalar ax = std::abs(x);
287   UnsignedInteger k0 = 12;
288   if (ax >= 35.0) k0 = 9;
289   if (ax >= 50.0) k0 = 7;
290   Scalar valueI0 = 1.0;
291   Scalar valueI1 = 1.0;
292   const Scalar xR = 1.0 / ax;
293   Scalar xRPow = xR;
294   for (UnsignedInteger k = 0; k < k0; ++k)
295   {
296     valueI0 += A[k] * xRPow;
297     valueI1 += B[k] * xRPow;
298     xRPow *= xR;
299   }
300   return std::log(valueI1) - std::log(valueI0);
301 }
302 
DeltaLogBesselI10(const Scalar x)303 Scalar SpecFunc::DeltaLogBesselI10(const Scalar x)
304 {
305   if (!(x > 0.0)) return LowestScalar;
306   // Small argument. The threshold is such that the relative error is less than
307   // epsilon machine in double precision (Maple)
308   if (!(x > 0.848296173838189821792665527416e-2)) return std::log(0.5 * x) + x * x * (-0.125 + 5.0 * x * x / 384.0);
309   // Medium argument
310   if (!(x > 22.0)) return std::log(SmallCaseBesselI1(x) / SmallCaseBesselI0(x));
311   // Large argument
312   else return LargeCaseDeltaLogBesselI10(x);
313 }
314 
315 class LogBesselKIntegrandEvaluation : public EvaluationImplementation
316 {
317 public:
LogBesselKIntegrandEvaluation(const Scalar nu,const Scalar x)318   LogBesselKIntegrandEvaluation(const Scalar nu, const Scalar x) : EvaluationImplementation(), nu_(nu), x_(x) {}
clone() const319   LogBesselKIntegrandEvaluation * clone() const override
320   {
321     return new LogBesselKIntegrandEvaluation(*this);
322   }
getInputDimension() const323   UnsignedInteger getInputDimension() const override
324   {
325     return 1;
326   }
getOutputDimension() const327   UnsignedInteger getOutputDimension() const override
328   {
329     return 1;
330   }
331 
operator ()(const Point & inP) const332   Point operator()(const Point & inP) const override
333   {
334     const Scalar t = inP[0];
335     Point outP(1);
336     if (nu_ == 0)
337       outP[0] = exp(-x_ * cosh(t));
338     else
339       outP[0] = exp(-x_ * cosh(t)) * std::pow(sinh(t), 2.0 * nu_);
340     return outP;
341   }
342 
343 private:
344   Scalar nu_ = 0.0;
345   Scalar x_ = 0.0;
346 };
347 
348 // Logarithm of the modified second kind Bessel function of order nu: LogBesselK(nu, x)=log(\frac{\pi}{2}\frac{I_{-\nu}(x)-I_[\nu}(x)}{\sin{\nu\pi}})
LogBesselK(const Scalar nu,const Scalar x)349 Scalar SpecFunc::LogBesselK(const Scalar nu,
350                             const Scalar x)
351 {
352   if (!(x > 0.0)) throw InvalidArgumentException(HERE) << "Error: x must be positive, here x=" << x;
353   // Reflection formula
354   if (nu < 0.0) return LogBesselK(-nu, x);
355   // Special cases
356   if (nu == 0.5) return 0.5 * std::log(M_PI / (2.0 * x)) - x;
357   if (nu == 1.5)
358   {
359     const Scalar num = 1.0 + 1.0 / x;
360     return 0.5 * std::log(M_PI * num * num / (2.0 * x)) - x;
361   }
362   if (nu == 2.5)
363   {
364     const Scalar num = 1.0 + (3.0 / x) * (1.0 + 1.0 / x);
365     return 0.5 * std::log(M_PI * num * num / (2.0 * x)) - x;
366   }
367 #ifdef OPENTURNS_HAVE_BOOST
368   return std::log(boost::math::cyl_bessel_k(nu, x));
369 #else
370   Scalar logFactor = 0.0;
371   const Function integrand(LogBesselKIntegrandEvaluation(nu, x));
372   UnsignedInteger precision = PlatformInfo::GetNumericalPrecision();
373   PlatformInfo::SetNumericalPrecision(16);
374   Scalar upper = -1.0;
375   if (nu == 0.0)
376   {
377     upper = std::log(-2.0 * std::log(ScalarEpsilon) / x);
378   }
379   else
380   {
381     logFactor = nu * std::log(0.5 * x) - LogGamma(0.5 + nu) + 0.5 * std::log(M_PI);
382     upper = std::log(ScalarEpsilon) / (2.0 * nu) - LambertW(-0.25 * x * std::exp(0.5 * std::log(ScalarEpsilon) / nu) / nu, false);
383   }
384   Scalar epsilon = -1.0;
385   const Scalar integral = GaussKronrod().integrate(integrand, Interval(ScalarEpsilon, upper), epsilon)[0];
386   PlatformInfo::SetNumericalPrecision(precision);
387   if (!IsNormal(integral) || (integral == 0.0)) return LowestScalar;
388   return logFactor + std::log(integral);
389 #endif
390 }
391 
392 // Modified second kind Bessel function of order nu: BesselK(nu, x)=\frac{\pi}{2}\frac{I_{-\nu}(x)-I_[\nu}(x)}{\sin{\nu\pi}}
BesselK(const Scalar nu,const Scalar x)393 Scalar SpecFunc::BesselK(const Scalar nu,
394                          const Scalar x)
395 {
396 #ifdef OPENTURNS_HAVE_BOOST
397   return boost::math::cyl_bessel_k(nu, x);
398 #else
399   if (!(x > 0.0)) throw InvalidArgumentException(HERE) << "Error: x must be positive, here x=" << x;
400   // Reflection formula
401   if (nu < 0.0) return BesselK(-nu, x);
402   // First the limit cases
403   if ((std::abs(x) < 0.0056) && (nu == 0.0))
404   {
405     const Scalar logX = std::log(x);
406     const Scalar x2 = 0.25 * x * x;
407     return M_LN2 - logX - EulerConstant + x2 * (M_LN2 - logX + 1.0 - EulerConstant + 0.25 * x2 * (M_LN2 - logX + 1.5 - EulerConstant));
408   }
409   if (std::abs(x) < 1e-8) return 0.5 * std::exp(LogGamma(nu) - nu * std::log(0.5 * x));
410   if ((std::abs(x) > 1e4) && (x > nu)) return std::sqrt(M_PI / (2.0 * x)) * std::exp(-x);
411   const Scalar logK = LogBesselK(nu, x);
412   if (logK >= LogMaxScalar) return MaxScalar;
413   return std::exp(logK);
414 #endif
415 }
416 
417 // Modified second kind Bessel derivative function of order nu: BesselKDerivative(nu, x)=dBesselK(nu, x) / dx
BesselKDerivative(const Scalar nu,const Scalar x)418 Scalar SpecFunc::BesselKDerivative(const Scalar nu,
419                                    const Scalar x)
420 {
421 #if defined(OPENTURNS_HAVE_BOOST) && (BOOST_VERSION >= 105600)
422   return boost::math::cyl_bessel_k_prime(nu, x);
423 #else
424   if (x == 0.0) return LowestScalar;
425   return -0.5 * (BesselK(nu - 1, x) + BesselK(nu + 1.0, x));
426 #endif
427 }
428 
429 // LnBeta function: LnBeta(a, b) = \log(Beta(a, b))
LnBeta(const Scalar a,const Scalar b)430 Scalar SpecFunc::LnBeta(const Scalar a,
431                         const Scalar b)
432 {
433   const Scalar first = std::min(a, b);
434   if (!(first > 0.0)) throw InvalidArgumentException(HERE) << "Error: cannot compute the LogBeta function when a or b is nonpositive, a=" << a << ", b=" << b;
435   const Scalar second = std::max(a, b);
436   const Scalar sum = a + b;
437   // Common case: a and b small
438   if (second < 7.75) return lgamma(first) - lgamma(sum) + lgamma(second);
439   const Scalar correctionSecond = GammaCorrection(second);
440   const Scalar correctionSum = GammaCorrection(sum);
441   // Case a and b large
442   if (first >= 7.75)
443   {
444     // b not very large wrt a
445     if (second < 103.25 * first) return correctionSecond - correctionSum + GammaCorrection(first) - 0.5 * std::log(second) + second * std::log(second / first) + (sum - 0.5) * log1p(-second / sum) + LOGSQRT2PI;
446     else
447     {
448       const Scalar epsilon = 1.0 / second;
449       Scalar value = std::log(epsilon);
450       // Here we use an expansion of (log(Gamma(b)) - log(Gamma(a+b))) / a - log(b) pour a << b
451       // The expansion is in double Padé form wrt a and b
452       const Scalar c1 = -1.0 + first;
453       const Scalar c2 = c1 * (2 * first - 1);
454       const Scalar c3 = c1 * c1;
455       const Scalar c4 = -6.0 + 3.0 * first;
456       const Scalar c5 = first * first;
457       value += epsilon * (-0.5 * c1 + epsilon * (c2 / 12.0 + epsilon * (-(c3 * first) / 12.0 + epsilon * (((-1.0 + 3.0 * first * c1) * c2) / 120.0 + epsilon * (-(c3 * (-1.0 + 2.0 * first * c1) * first) / 60.0 + epsilon * (((1.0 + first * (3.0 + c5 * c4)) * c2) / 252.0 + epsilon * (-(c3 * (2.0 + first * (4.0 + first * (-1.0 + first * c4))) * first) / 168.0 + ((-3.0 + (-9.0 + (-1.0 + (15.0 + (5.0 + (-15.0 + 5.0 * first) * first) * first) * first) * first) * first) * epsilon * c2) / 720.0)))))));
458       value *= first;
459       value += LogGamma(first);
460       return value;
461     }
462   }
463   // Case one of a,b large, the other small
464   return LogGamma(first) + correctionSecond - correctionSum + first * (1.0 - std::log(sum)) + (second - 0.5) * log1p(-first / sum);
465 }
466 
467 // LogBeta = LnBeta
LogBeta(const Scalar a,const Scalar b)468 Scalar SpecFunc::LogBeta(const Scalar a,
469                          const Scalar b)
470 {
471   return LnBeta(a, b);
472 }
473 
474 // Beta function: Beta(a, b) = \int_0^1 t^{a-1}(1-t)^{b-1} dt
Beta(const Scalar a,const Scalar b)475 Scalar SpecFunc::Beta(const Scalar a,
476                       const Scalar b)
477 {
478   return std::exp(LnBeta(a, b));
479 }
480 
481 // Incomplete Beta function: BetaInc(a, b, x) = \int_0^x t^{a-1}(1-t)^{b-1} dt
IncompleteBeta(const Scalar a,const Scalar b,const Scalar x,const Bool tail)482 Scalar SpecFunc::IncompleteBeta(const Scalar a,
483                                 const Scalar b,
484                                 const Scalar x,
485                                 const Bool tail)
486 {
487   return RegularizedIncompleteBeta(a, b, x, tail) * Beta(a, b);
488 }
489 
490 // Incomplete Beta function inverse
IncompleteBetaInverse(const Scalar a,const Scalar b,const Scalar x,const Bool tail)491 Scalar SpecFunc::IncompleteBetaInverse(const Scalar a,
492                                        const Scalar b,
493                                        const Scalar x,
494                                        const Bool tail)
495 {
496   return RegularizedIncompleteBetaInverse(a, b, x / Beta(a, b), tail);
497 }
498 
499 // Regularized Incomplete Beta function: RegularizedIncompleteBeta(a, b, x) = 1/beta(a, b) * \int_0^x t^{a-1}(1-t)^{b-1} dt
RegularizedIncompleteBeta(const Scalar a,const Scalar b,const Scalar x,const Bool tail)500 Scalar SpecFunc::RegularizedIncompleteBeta(const Scalar a,
501     const Scalar b,
502     const Scalar x,
503     const Bool tail)
504 {
505   return BetaFunctions::RegularizedIncompleteBeta(a, b, x, tail);
506 }
507 
508 // Regularized incomplete Beta Function inverse
RegularizedIncompleteBetaInverse(const Scalar a,const Scalar b,const Scalar x,const Bool tail)509 Scalar SpecFunc::RegularizedIncompleteBetaInverse(const Scalar a,
510     const Scalar b,
511     const Scalar x,
512     const Bool tail)
513 {
514   return BetaFunctions::RegularizedIncompleteBetaInverse(a, b, x, tail);
515 }
516 
517 // Dawson function: Dawson(x) = \exp(-x^2) * \int_0^x \exp(t^2) dt
Dawson(const Scalar x)518 Scalar SpecFunc::Dawson(const Scalar x)
519 {
520   return Faddeeva::Dawson(x);
521 }
522 
Dawson(const Complex & z)523 Complex SpecFunc::Dawson(const Complex & z)
524 {
525   return Faddeeva::Dawson(z);
526 }
527 
528 // Debye function of order n: DebyeN(x, n) = n / x^n \int_0^x t^n/(\exp(t)-1) dt
Debye(const Scalar x,const UnsignedInteger n)529 Scalar SpecFunc::Debye(const Scalar x,
530                        const UnsignedInteger n)
531 {
532   if (!(n > 0 && n <= 20)) throw InvalidArgumentException(HERE) << "Error: cannot compute Debye function of order outside of {1,...,20}, here order=" << n;
533   if (x < 0.0) return Debye(-x, n) - n * x / (n + 1.0);
534   // The threshold is such that the overall error is less than 1.0e-16
535   if (x < 1.0e-8) return 1.0 - n * x / (2.0 * (n + 1.0));
536   return debyen(x, static_cast<int>(n)) * n / pow(x, static_cast<int>(n));
537 }
538 
539 // DiLog function: DiLog(x) = -\int_0^x \log(1-t)/t dt
DiLog(const Scalar x)540 Scalar SpecFunc::DiLog(const Scalar x)
541 {
542   // Special case for 0
543   if (x == 0.0) return 0.0;
544   // Special case for 1
545   if (x == 1.0) return PI2_6;
546   // No real value on (1, \infty)
547   if (!(x <= 1.0)) throw InvalidArgumentException(HERE) << "Error: the DiLog function does not take real values for arguments greater than 1, here argument=" << x;
548   // Special case for x close to 1
549   if (x >= 0.999997)
550   {
551     const Scalar z = 1.0 - x;
552     const Scalar logZ = std::log(z);
553     return PI2_6 + z * (logZ - 1.0 + z * (logZ - 0.5) * 0.5);
554   }
555   // Use DiLog(x) = -DiLog(1 / x) - \pi^2 / 6 - \log^2(-x) / 2
556   // to map (-\infty, -1) into (-1, 0) for the argument
557   if (x < -1.0) return -DiLog(1.0 / x) - PI2_6  - 0.5 * pow(log(-x), 2);
558   // Use DiLog(x) = DiLog(x^2) / 2 - DiLog(-x)
559   // to map [-1, 0) into (0, 1]
560   if (x < 0.0) return 0.5 * DiLog(x * x) - DiLog(-x);
561   // Use DiLog(x) = \pi^2 / 6 - DiLog(1 - x) - \log(x)\log(1-x)
562   // to map (1/2, 1] into [0, 1/2)
563   if (x > 0.5) return PI2_6 - DiLog(1.0 - x) - std::log(x) * log1p(-x);
564   // Use the definition of DiLog in terms of series
565   // DiLog(x)=\sum_{k=1}^{\infty} x^k/k^2
566   // for (0, 1/2)
567   // This upper bound is an easy-to compute tight upper bound of the number of iterations
568   const UnsignedInteger nMax = static_cast<UnsignedInteger>(round(8 + 68 * x));
569   Scalar value = 0.0;
570   Scalar powerX = 1.0;
571   for (UnsignedInteger n = 1; n <= nMax; ++n)
572   {
573     powerX *= x;
574     value += powerX / (n * n);
575   }
576   return value;
577 }
578 
579 // Exponential integral function: Ei(x) = -\int_{-x}^{\infty}exp(-t)/t dt
Ei(const Scalar x)580 Scalar SpecFunc::Ei(const Scalar x)
581 {
582   return ExponentialIntegralFunctions::Ei(x);
583 }
584 
585 // Complex exponential integral function: Ei(z) = -\int_{-z}^{\infty}exp(-t)/t dt
Ei(const Complex & z)586 Complex SpecFunc::Ei(const Complex & z)
587 {
588   return ExponentialIntegralFunctions::Ei(z);
589 }
590 
591 // Complex Faddeeva function: faddeeva(z) = \exp(-z^2)\erfc(-I*z)
Faddeeva(const Complex & z)592 Complex SpecFunc::Faddeeva(const Complex & z)
593 {
594   return Faddeeva::w(z);
595 }
596 
FaddeevaIm(const Scalar x)597 Scalar SpecFunc::FaddeevaIm(const Scalar x)
598 {
599   return Faddeeva::w_im(x);
600 }
601 
602 // Factorial function
LogFactorial(const UnsignedInteger n)603 Scalar SpecFunc::LogFactorial(const UnsignedInteger n)
604 {
605   static Scalar A[128] = {0.0, 0.0, 0.69314718055994531, 1.7917594692280550, 3.1780538303479456, 4.7874917427820460, 6.5792512120101010, 8.5251613610654143, 10.604602902745250, 12.801827480081470, 15.104412573075515, 17.502307845873886, 19.987214495661886, 22.552163853123423, 25.191221182738682, 27.899271383840892, 30.671860106080673, 33.505073450136889, 36.395445208033054, 39.339884187199494, 42.335616460753485, 45.380138898476908, 48.471181351835224, 51.606675567764374, 54.784729398112319, 58.003605222980520, 61.261701761002002, 64.557538627006331, 67.889743137181535, 71.257038967168009, 74.658236348830164, 78.092223553315311, 81.557959456115037, 85.054467017581517, 88.580827542197679, 92.136175603687092, 95.719694542143202, 99.330612454787427, 102.96819861451381, 106.63176026064346, 110.32063971475740, 114.03421178146170, 117.77188139974507, 121.53308151543863, 125.31727114935690, 129.12393363912721, 132.95257503561631, 136.80272263732637, 140.67392364823426, 144.56574394634489, 148.47776695177303, 152.40959258449736, 156.36083630307879, 160.33112821663091, 164.32011226319518, 168.32744544842765, 172.35279713916280, 176.39584840699735, 180.45629141754377, 184.53382886144949, 188.62817342367159, 192.73904728784490, 196.86618167288999, 201.00931639928153, 205.16819948264120, 209.34258675253684, 213.53224149456326, 217.73693411395423, 221.95644181913033, 226.19054832372759, 230.43904356577695, 234.70172344281827, 238.97838956183432, 243.26884900298271, 247.57291409618688, 251.89040220972319, 256.22113555000953, 260.56494097186321, 264.92164979855280, 269.29109765101982, 273.67312428569370, 278.06757344036614, 282.47429268763040, 286.89313329542699, 291.32395009427031, 295.76660135076062, 300.22094864701413, 304.68685676566872, 309.16419358014692, 313.65282994987906, 318.15263962020933, 322.66349912672618, 327.18528770377522, 331.71788719692847, 336.26118197919848, 340.81505887079902, 345.37940706226685, 349.95411804077024, 354.53908551944081, 359.13420536957540, 363.73937555556349, 368.35449607240475, 372.97946888568902, 377.61419787391866, 382.25858877306003, 386.91254912321755, 391.57598821732962, 396.24881705179153, 400.93094827891575, 405.62229616114489, 410.32277652693731, 415.03230672824964, 419.75080559954473, 424.47819341825707, 429.21439186665157, 433.95932399501482, 438.71291418612118, 443.47508812091894, 448.24577274538461, 453.02489623849614, 457.81238798127818, 462.60817852687492, 467.41219957160818, 472.22438392698060, 477.04466549258563, 481.87297922988793, 486.70926113683941, 491.55344822329800};
606   if (n < 128) return A[n];
607   /* Stieltjes approximation, see http://www.luschny.de/math/factorial/approx/SimpleCases.html */
608   static Scalar a0 = 1.0 / 12.0;
609   static Scalar a1 = 1.0 / 30.0;
610   static Scalar a2 = 53.0 / 210.0;
611   static Scalar a3 = 195.0 / 371.0;
612   static Scalar a4 = 22999.0 / 22737.0;
613   static Scalar a5 = 29944523.0 / 19733142.0;
614   static Scalar a6 = 109535241009.0 / 48264275462.0;
615   const Scalar z = n + 1.0;
616   return LOGSQRT2PI + (z - 0.5) * std::log(z) - z + a0 / (z + a1 / (z + a2 / (z + a3 / (z + a4 / (z + a5 / (z + a6 / z))))));
617 }
618 
Factorial(const UnsignedInteger n)619 Scalar SpecFunc::Factorial(const UnsignedInteger n)
620 {
621   if (n < LogMaxScalar) return std::exp(LogFactorial(n));
622   throw InternalException(HERE) << "Error: n=" << n << " is too large for n! to fit into the return type";
623   return MaxScalar;
624 }
625 
626 // Gamma function: Gamma(a) = \int_0^{\infty} t^{a-1}\exp(-t) dt
Gamma(const Scalar a)627 Scalar SpecFunc::Gamma(const Scalar a)
628 {
629   return tgamma(a);
630 }
631 
632 // igamma1pm1(a) = 1 / Gamma(1 + a) - 1
IGamma1pm1(const Scalar a)633 Scalar SpecFunc::IGamma1pm1(const Scalar a)
634 {
635   if (a < -0.5) return a + IGamma1pm1(a + 1.0);
636   if (a > 0.5) return (IGamma1pm1(a - 1.0) - a) / (1.0 + a);
637   return a * (0.55840397973848040460 +    (-0.28693519326375203685 +
638               (-0.28661639813928077048 +     (0.56469202267873782108e-2 +
639                   (0.12419086997568707715e-1 + (-0.28455238049924868708e-2 +
640                       (-0.11632361891621759586e-3 +   0.43452535150473018757e-4 * a) * a) * a) * a) * a) * a) * a) /
641          (0.967409607349687017271 +    (0.602145048219053169110 +
642                                         (0.258051013832915714221 +    (0.677000815494264186575e-1 +
643                                             (0.142113296913915958898e-1 + (0.183821175266489590252e-2 +
644                                                 0.192078142776918599109e-3 * a) * a) * a) * a) * a) * a);
645 }
646 
647 // GammaCorrection(a) = LogGamma(a) - log(sqrt(2.Pi)) + a - (a - 1/2) log(a)
GammaCorrection(const Scalar a)648 Scalar SpecFunc::GammaCorrection(const Scalar a)
649 {
650   if (!(a > 0.0)) throw InvalidArgumentException(HERE) << "Error: cannot compute GammaCorrection for nonpositive a, here a=" << a;
651   // Use an asymptotic series for large argument
652   if (a > 7.7490453948312251620)
653   {
654     const Scalar ia2 = 1.0 / (a * a);
655     return (0.83333333333333333333e-1 + (-0.27777777777777777778e-2 +
656                                          (0.79365079365079365079e-3 + (-0.59523809523809523810e-3 +
657                                              (0.84175084175084175084e-3 + (-0.19175269175269175269e-2 +
658                                                  (0.64102564102564102564e-2 + (-0.29550653594771241830e-1 +
659                                                      (0.17964437236883057316e0 - 0.13924322169059011164e1 * ia2) * ia2) * ia2) * ia2) * ia2) * ia2) * ia2) * ia2) * ia2) / a;
660   }
661   return LogGamma(a) + a - (a - 0.5) * std::log(a) - LOGSQRT2PI;
662 }
663 
664 // Complex gamma function: Gamma(a) = \int_0^{\infty} t^{a-1}\exp(-t) dt,
665 // Computed using Lanczos approximation, using a C++ translation of
666 // Paul Godfrey's matlab implementation
667 // http://home.att.net/~numericana/answer/info/godfrey.htm#matlabgamma
Gamma(const Complex & a)668 Complex SpecFunc::Gamma(const Complex & a)
669 {
670   if (a.imag() == 0.0) return Gamma(a.real());
671   return std::exp(LogGamma(a));
672 }
673 
LogGamma(const Complex & a)674 Complex SpecFunc::LogGamma(const Complex & a)
675 {
676   if (a.imag() == 0.0) return LogGamma(a.real());
677   const Scalar sqrt2Pi = sqrt(2.0 * M_PI);
678   Complex z(a);
679   Bool flip = false;
680   if (z.real() < 0.0)
681   {
682     z = -z;
683     flip = true;
684   }
685   const UnsignedInteger coefficientsSize = 11;
686   static const Scalar coefficients[coefficientsSize] =
687   {
688     1.000000000000000174663,      5716.400188274341379136,
689     -14815.30426768413909044,     14291.49277657478554025,
690     -6348.160217641458813289,     1301.608286058321874105,
691     -108.1767053514369634679,     2.605696505611755827729,
692     -0.7423452510201416151527e-2, 0.5384136432509564062961e-7,
693     -0.4023533141268236372067e-8
694   };
695   const Scalar g = coefficientsSize - 2.0;
696   Complex t(z + g);
697   Complex s(0.0);
698   Complex ss(t - 0.5);
699   for (UnsignedInteger k = coefficientsSize - 1; k > 0; --k)
700   {
701     s += coefficients[k] / t;
702     t -= 1.0;
703   }
704   s += coefficients[0];
705   s = std::log(s * sqrt2Pi) + (z - 0.5) * std::log(ss) - ss;
706   Complex f(s);
707   if (flip) f = f + Log1p(-M_PI * std::exp(-f) / (a * f * sin(M_PI * a)));
708   return f;
709 }
710 
711 // Natural logarithm of the Gamma function
LnGamma(const Scalar a)712 Scalar SpecFunc::LnGamma(const Scalar a)
713 {
714   return LogGamma(a);
715 }
716 
717 // LogGamma = LnGamma
LogGamma(const Scalar a)718 Scalar SpecFunc::LogGamma(const Scalar a)
719 {
720   return lgamma(a);
721 }
722 
LogGamma1p(const Scalar a)723 Scalar SpecFunc::LogGamma1p(const Scalar a)
724 {
725   return (std::abs(a) < 0.5 ? -a * (0.34229051727072805652 +
726                                     (0.75305954018877769214 +
727                                      (0.25594427350421023219 +
728                                       (-0.54867134418632830931 +
729                                        (-0.57006260085649768851 +
730                                         (-0.20361938002564003637 +
731                                          (-0.27922966566918143201e-1 -
732                                           0.10180389882069314488e-2 * a) * a) * a) * a) * a) * a) * a) /
733           (0.59300282040876235168 +
734            (0.21496034951064079616e1 +
735             (0.30947091018029240660e1 +
736              (0.22448538584537209829e1 +
737               (0.85741167089803858333 +
738                (0.16321946228463159159 +
739                 (0.12893353820029086191e-1 +
740                  0.24787923059095734273e-3 * a) * a) * a) * a) * a) * a) * a) : LogGamma(a - 1.0));
741 }
742 
743 // Incomplete Gamma function: IncompleteGamma(a, x) = \int_0^x t^{a-1}\exp(-t) dt
IncompleteGamma(const Scalar a,const Scalar x,const Bool tail)744 Scalar SpecFunc::IncompleteGamma(const Scalar a,
745                                  const Scalar x,
746                                  const Bool tail)
747 {
748   return GammaFunctions::IncompleteGamma(a, x, tail);
749 }
750 
751 // Incomplete Gamma function inverse with respect to x
IncompleteGammaInverse(const Scalar a,const Scalar x,const Bool tail)752 Scalar SpecFunc::IncompleteGammaInverse(const Scalar a,
753                                         const Scalar x,
754                                         const Bool tail)
755 {
756   return GammaFunctions::IncompleteGammaInverse(a, x, tail);
757 }
758 
759 // Regularized incomplete Gamma function: RegularizedIncompleteGamma(a, x) = \int_0^x t^{a-1}\exp(-t) dt / \Gamma(a)
RegularizedIncompleteGamma(const Scalar a,const Scalar x,const Bool tail)760 Scalar SpecFunc::RegularizedIncompleteGamma(const Scalar a,
761     const Scalar x,
762     const Bool tail)
763 {
764   return GammaFunctions::RegularizedIncompleteGamma(a, x, tail);
765 }
766 
767 // Regularized incomplete Gamma function inverse with respect to x
RegularizedIncompleteGammaInverse(const Scalar a,const Scalar x,const Bool tail)768 Scalar SpecFunc::RegularizedIncompleteGammaInverse(const Scalar a,
769     const Scalar x,
770     const Bool tail)
771 {
772   return GammaFunctions::RegularizedIncompleteGammaInverse(a, x, tail);
773 }
774 
775 // Digamma function: Psi(x) = ((dgamma/dx) / gamma)(x)
776 // Derivative of a Lanczos approximation of log(Gamma)
DiGamma(const Scalar x)777 Scalar SpecFunc::DiGamma(const Scalar x)
778 {
779   // Check that the argument is not non positive, i.e. not in {0, -1, -2, ...}
780   if ((x <= 0.0) && (x == round(x))) throw InvalidArgumentException(HERE) << "Error: the argument of the DiGamma function cannot be a non positive integer.";
781   // Approximation for small arguments
782   // Here, 0.025 is a bound that insure Scalar precision approximation
783   if ( std::abs(x) <= 0.025 ) return -1.0 / x - 0.57721566490153286 + (1.6449340668482264 + (-1.2020569031595943 + (1.0823232337111381 + (-1.0369277551433699 + (1.0173430619844491 + (-1.0083492773819228 + (1.0040773561979442 + (-1.0020083928260822 + 1.0009945751278180 * x) * x) * x) * x) * x) * x) * x) * x) * x;
784   // If the argument is negative, use the reflexion formula
785   if (x < 0.0) return -M_PI / tan(M_PI * x) + DiGamma(1.0 - x);
786   // Shift the argument until it reaches the asymptotic expansion region
787   // Here, 7.69 is a bound that insure Scalar precision of the approximation
788   Scalar z = x;
789   Scalar value = 0.0;
790   while ( z < 7.33 )
791   {
792     value -= 1.0 / z;
793     z += 1.0;
794   }
795   // Use the asymptotic expansion in Horner form
796   const Scalar y = 1.0 / (z * z);
797   return value + std::log(z) - 0.5 / z + (-0.83333333333333333e-1 + (0.83333333333333333e-2 + (-0.39682539682539683e-2 + (0.41666666666666667e-2 + (-0.75757575757575758e-2 + (0.21092796092796093e-1 + (-0.83333333333333333e-1 + (.44325980392156863 - 3.0539543302701197 * y) * y) * y) * y) * y) * y) * y) * y) * y;
798 }
799 
Psi(const Scalar x)800 Scalar SpecFunc::Psi(const Scalar x)
801 {
802   return DiGamma(x);
803 }
804 
805 // Inverse of the DiGamma function
DiGammaInv(const Scalar a)806 Scalar SpecFunc::DiGammaInv(const Scalar a)
807 {
808   // Initialization using an asymptotic approximation of the DiGamma function
809   Scalar x = a < -2.22 ? -1.0 / (a - EulerConstant) : std::exp(a) + 0.5;
810   // Use a Newton scheme
811   Scalar d = 0.0;
812   for (UnsignedInteger k = 0; k < 6; ++k)
813   {
814     d = (DiGamma(x) - a) / TriGamma(x);
815     if (d == 0.0) break;
816     x -= d;
817   }
818   return x;
819 }
820 
821 // Trigamma function: TriGamma(x) = ((d^2gamma/dx^2) / gamma)(x)
TriGamma(const Scalar x)822 Scalar SpecFunc::TriGamma(const Scalar x)
823 {
824   // Check that the argument is not non positive, i.e. not in {0, -1, -2, ...}
825   if ((x <= 0.0) && (x == round(x))) throw InvalidArgumentException(HERE) << "Error: the argument of the TriGamma function cannot be a non positive integer.";
826   // Approximation for small arguments
827   // Here, 0.02 is a bound that insure Scalar precision approximation
828   if ( std::abs(x) <= 0.02 ) return 1.0 / (x * x) + 1.6449340668482264 + (-2.4041138063191886 + (3.2469697011334144 + (-4.1477110205734796 + (5.0867153099222453 + (-6.0500956642915368 + (7.0285414933856097 + (-8.0160671426086576 + (9.0089511761503616 - 10.004941886041195 * x) * x) * x) * x) * x) * x) * x) * x) * x;
829   // If the argument is negative, use the reflexion formula
830   if (x < 0.0) return pow(M_PI / sin(M_PI * x), 2.0) - TriGamma(1.0 - x);
831   // Shift the argument until it reaches the asymptotic expansion region
832   // Here, 7.69 is a bound that insure Scalar precision of the approximation
833   Scalar z = x;
834   Scalar value = 0.0;
835   while ( z < 7.69 )
836   {
837     value += 1.0 / (z * z);
838     z += 1.0;
839   }
840   // Use the asymptotic expansion in Horner form
841   const Scalar y = 1.0 / (z * z);
842   return value + 0.5 * y + (1. + (.16666666666666667 + (-0.33333333333333333e-1 + (0.23809523809523810e-1 + (-0.33333333333333333e-1 + (0.75757575757575758e-1 + (-.25311355311355311 + (1.1666666666666667 + (-7.0921568627450980 + 54.971177944862155 * y) * y) * y) * y) * y) * y) * y) * y) * y) / z;
843 }
844 
845 /* Stirlerr(n) = log(n!) - log( sqrt(2*pi*n)*(n/e)^n )
846 *     = log Gamma(n+1) - 1/2 * [log(2*pi) + log(n)] - n*[log(n) - 1]
847 *     = log Gamma(n+1) - (n + 1/2) * log(n) + n - log(2*pi)/2 */
Stirlerr(const UnsignedInteger n)848 Scalar SpecFunc::Stirlerr(const UnsignedInteger n)
849 {
850   static const Scalar stirlerrTable[26] =
851   {
852     0.000000000000000000000, 8.10614667953272582e-02, 4.13406959554092941e-02,
853     2.76779256849983391e-02, 2.07906721037650931e-02, 1.66446911898211922e-02,
854     1.38761288230707480e-02, 1.18967099458917701e-02, 1.04112652619720965e-02,
855     9.25546218271273292e-03, 8.33056343336287126e-03, 7.57367548795184079e-03,
856     6.94284010720952987e-03, 6.40899418800420707e-03, 5.95137011275884774e-03,
857     5.55473355196280137e-03, 5.20765591960964044e-03, 4.90139594843473786e-03,
858     4.62915374933402859e-03, 4.38556024923232427e-03, 4.16631969199692246e-03,
859     3.96795421864085962e-03, 3.78761806844443458e-03, 3.62296022468309471e-03,
860     3.47202138297876696e-03, 3.33315563672809288e-03
861   };
862   if (n < 26) return stirlerrTable[n];
863   static Scalar S0 = 8.33333333333333333e-02;
864   static Scalar S1 = 2.77777777777777778e-03;
865   static Scalar S2 = 7.93650793650793651e-04;
866   static Scalar S3 = 5.95238095238095238e-04;
867   static Scalar S4 = 8.41750841750841751e-04;
868   const Scalar nn = (1.0 * n) * n;
869   if (n > 2559) return (S0 - S1 / nn) / n;
870   if (n > 82)  return (S0 - (S1 - S2 / nn) / nn) / n;
871   if (n > 50)  return (S0 - (S1 - (S2 - S3 / nn) / nn) / nn) / n;
872   return (S0 - (S1 - (S2 - (S3 - S4 / nn) / nn) / nn) / nn) / n;
873 }
874 
875 // Hypergeometric function of type (1,1): HyperGeom_1_1(p1, q1, x) = \sum_{n=0}^{\infty} [\prod_{k=0}^{n-1} (p1 + k) / (q1 + k)] * x^n / n!
HyperGeom_1_1(const Scalar p1,const Scalar q1,const Scalar x)876 Scalar SpecFunc::HyperGeom_1_1(const Scalar p1,
877                                const Scalar q1,
878                                const Scalar x)
879 {
880   if (q1 == p1) return std::exp(x);
881   if (x == 0) return 1.0;
882 #ifdef OPENTURNS_HAVE_MPFR
883   boost::multiprecision::mpfr_float_500 pochhammerP1(p1);
884   boost::multiprecision::mpfr_float_500 pochhammerQ1(q1);
885   boost::multiprecision::mpfr_float_500 factorial(1.0);
886   boost::multiprecision::mpfr_float_500 term(1.0);
887   boost::multiprecision::mpfr_float_500 sum(term);
888   boost::multiprecision::mpfr_float_500 eps(1.0);
889   boost::multiprecision::mpfr_float_500 z(x);
890   Bool absEps = abs(eps) > Precision;
891   Bool absEpsPrec = absEps;
892   do
893   {
894     absEpsPrec = absEps;
895     term *= pochhammerP1 * z / (pochhammerQ1 * factorial);
896     pochhammerP1 += 1.0;
897     pochhammerQ1 += 1.0;
898     factorial += 1.0;
899     sum += term;
900     eps = term / sum;
901     absEps = abs(eps) > Precision;
902   }
903   while (absEps || absEpsPrec);
904   return sum.convert_to<Scalar>();
905 
906 #else
907   Scalar term = 1.0;
908   Scalar t = x;
909   Scalar pochhammerP1 = p1;
910   if (x < 0)
911   {
912     pochhammerP1 = q1 - p1;
913     t = -x;
914     term = std::exp(x);
915   }
916   Scalar pochhammerQ1 = q1;
917   Scalar factorial = 1.0;
918   Scalar sum = term;
919   Scalar eps = 1.0;
920   Bool absEps = std::abs(eps) > Precision;
921   Bool absEpsPrec = absEps;
922   do
923   {
924     absEpsPrec = absEps;
925     term *= pochhammerP1 * t / (pochhammerQ1 * factorial);
926     ++pochhammerP1;
927     ++pochhammerQ1;
928     ++factorial;
929     sum += term;
930     eps = term / sum;
931     absEps = std::abs(eps) > Precision;
932   }
933   while (absEps || absEpsPrec);
934   return sum;
935 #endif
936 }
937 
938 // Complex hypergeometric function of type (1,1): HyperGeom_1_1(p1, q1, x) = \sum_{n=0}^{\infty} [\prod_{k=0}^{n-1} (p1 + k) / (q1 + k)] * x^n / n!
HyperGeom_1_1(const Scalar p1,const Scalar q1,const Complex & x)939 Complex SpecFunc::HyperGeom_1_1(const Scalar p1,
940                                 const Scalar q1,
941                                 const Complex & x)
942 {
943 #ifdef OPENTURNS_HAVE_MPC
944   LOGDEBUG("Use MPC implementation");
945   boost::multiprecision::mpc_complex_500 pochhammerP1(p1);
946   boost::multiprecision::mpc_complex_500 pochhammerQ1(q1);
947   boost::multiprecision::mpc_complex_500 factorial{1.0, 0.0};
948   boost::multiprecision::mpc_complex_500 term{1.0, 0.0};
949   boost::multiprecision::mpc_complex_500 sum(term);
950   boost::multiprecision::mpc_complex_500 eps{1.0, 0.0};
951   boost::multiprecision::mpc_complex_500 z(x);
952   Bool absEps = abs(eps) > Precision;
953   Bool absEpsPrec = absEps;
954   do
955   {
956     absEpsPrec = absEps;
957     term *= pochhammerP1 * z / (pochhammerQ1 * factorial);
958     pochhammerP1 += 1.0;
959     pochhammerQ1 += 1.0;
960     factorial += 1.0;
961     sum += term;
962     eps = term / sum;
963     absEps = abs(eps) > Precision;
964   }
965   while (absEps || absEpsPrec);
966   return sum.convert_to<Complex>();
967 #else
968   Complex pochhammerP1(p1);
969   Complex pochhammerQ1(q1);
970   Scalar factorial = 1.0;
971   Complex term(1.0);
972   Complex sum(term);
973   Complex eps(1.0);
974   Bool absEps = std::abs(eps) > Precision;
975   Bool absEpsPrec = absEps;
976   do
977   {
978     absEpsPrec = absEps;
979     term *= pochhammerP1 * x / (pochhammerQ1 * factorial);
980     pochhammerP1 += 1.0;
981     pochhammerQ1 += 1.0;
982     ++factorial;
983     sum += term;
984     eps = term / sum;
985     absEps = std::abs(eps) > Precision;
986   }
987   while (absEps || absEpsPrec);
988   return sum;
989 #endif
990 }
991 
992 // Hypergeometric function of type (2,1): HyperGeom_2_1(p1, p2, q1, x) = sum_{n=0}^{\infty} [prod_{k=0}^{n-1} (p1 + k) . (p2 + k) / (q1 + k)] * x^n / n!
HyperGeom_2_1(const Scalar p1,const Scalar p2,const Scalar q1,const Scalar x)993 Scalar SpecFunc::HyperGeom_2_1(const Scalar p1,
994                                const Scalar p2,
995                                const Scalar q1,
996                                const Scalar x)
997 {
998 #ifdef OPENTURNS_HAVE_MPFR
999   boost::multiprecision::mpfr_float_500 pochhammerP1(p1);
1000   boost::multiprecision::mpfr_float_500 pochhammerP2(p2);
1001   boost::multiprecision::mpfr_float_500 pochhammerQ1(q1);
1002   boost::multiprecision::mpfr_float_500 factorial(1.0);
1003   boost::multiprecision::mpfr_float_500 z(x);
1004   boost::multiprecision::mpfr_float_500 term(1.0);
1005   boost::multiprecision::mpfr_float_500 sum(term);
1006   boost::multiprecision::mpfr_float_500 eps(1.0);
1007   Bool absEps = abs(eps) > Precision;
1008   Bool absEpsPrec = absEps;
1009   do
1010   {
1011     absEpsPrec = absEps;
1012     term *= pochhammerP1 * pochhammerP2 * z / (pochhammerQ1 * factorial);
1013     ++pochhammerP1;
1014     ++pochhammerP2;
1015     ++pochhammerQ1;
1016     ++factorial;
1017     sum += term;
1018     eps = abs(term / sum);
1019     absEps = abs(eps) > Precision;
1020   }
1021   while (absEps || absEpsPrec);
1022   return sum.convert_to<Scalar>();
1023 #else
1024   Scalar pochhammerP1 = p1;
1025   Scalar pochhammerP2 = p2;
1026   Scalar pochhammerQ1 = q1;
1027   Scalar factorial = 1.0;
1028   Scalar term = 1.0;
1029   Scalar sum = term;
1030   Scalar eps = 1.0;
1031   Bool absEps = std::abs(eps) > Precision;
1032   Bool absEpsPrec = absEps;
1033   do
1034   {
1035     absEpsPrec = absEps;
1036     term *= pochhammerP1 * pochhammerP2 * x / (pochhammerQ1 * factorial);
1037     ++pochhammerP1;
1038     ++pochhammerP2;
1039     ++pochhammerQ1;
1040     ++factorial;
1041     sum += term;
1042     eps = std::abs(term / sum);
1043     absEps = std::abs(eps) > Precision;
1044   }
1045   while (absEps || absEpsPrec);
1046   return sum;
1047 #endif
1048 }
1049 
1050 // Hypergeometric function of type (2,2): HyperGeom_2_1(p1, p2, q1, q2, x) = sum_{n=0}^{\infty} [prod_{k=0}^{n-1} (p1 + k) . (p2 + k) / (q1 + k) / (q2 + k)] * x^n / n!
HyperGeom_2_2(const Scalar p1,const Scalar p2,const Scalar q1,const Scalar q2,const Scalar x)1051 Scalar SpecFunc::HyperGeom_2_2(const Scalar p1,
1052                                const Scalar p2,
1053                                const Scalar q1,
1054                                const Scalar q2,
1055                                const Scalar x)
1056 {
1057   if (x == 0.0) return 1.0;
1058 #ifdef OPENTURNS_HAVE_MPFR
1059   boost::multiprecision::mpfr_float_500 pochhammerP1(p1);
1060   boost::multiprecision::mpfr_float_500 pochhammerP2(p2);
1061   boost::multiprecision::mpfr_float_500 pochhammerQ1(q1);
1062   boost::multiprecision::mpfr_float_500 pochhammerQ2(q2);
1063   boost::multiprecision::mpfr_float_500 factorial(1.0);
1064   boost::multiprecision::mpfr_float_500 z(x);
1065   boost::multiprecision::mpfr_float_500 term(0.0);
1066   boost::multiprecision::mpfr_float_500 sum(term);
1067   boost::multiprecision::mpfr_float_500 eps(1.0);
1068   Bool absEps = abs(eps) > Precision;
1069   Bool absEpsPrec = absEps;
1070   do
1071   {
1072     absEpsPrec = absEps;
1073     term += pochhammerP1 * pochhammerP2 * z / (pochhammerQ1 * pochhammerQ2 * factorial);
1074     ++pochhammerP1;
1075     ++pochhammerP2;
1076     ++pochhammerQ1;
1077     ++pochhammerQ2;
1078     ++factorial;
1079     sum += term;
1080     eps = abs(term / sum);
1081     absEps = abs(eps) > Precision;
1082   }
1083   while (absEps || absEpsPrec);
1084   return sum.convert_to<Scalar>();
1085 #else
1086   Scalar pochhammerP1 = p1;
1087   Scalar pochhammerP2 = p2;
1088   Scalar pochhammerQ1 = q1;
1089   Scalar pochhammerQ2 = q2;
1090   Scalar factorial = 1.0;
1091   Scalar term = 0.0;
1092   Scalar sum = term;
1093   Scalar eps = 1.0;
1094   Bool absEps = std::abs(eps) > Precision;
1095   Bool absEpsPrec = absEps;
1096   const Scalar logX = std::log(std::abs(x));
1097   Scalar signX = x > 0.0 ? 1.0 : -1.0;
1098   Scalar signTerm = 1.0;
1099   do
1100   {
1101     absEpsPrec = absEps;
1102     term += std::log(pochhammerP1) + std::log(pochhammerP2) + logX - std::log(pochhammerQ1) - std::log(pochhammerQ2) - std::log(factorial);
1103     ++pochhammerP1;
1104     ++pochhammerP2;
1105     ++pochhammerQ1;
1106     ++pochhammerQ2;
1107     ++factorial;
1108     sum += signTerm * std::exp(term);
1109     signTerm *= signX;
1110     eps = std::abs(term / sum);
1111     absEps = std::abs(eps) > Precision;
1112   }
1113   while (absEps || absEpsPrec);
1114   return sum;
1115 #endif
1116 }
1117 
1118 // Erf function Erf(x) = 2 / sqrt(Pi) . \int_0^x \exp(-t^2) dt
Erf(const Scalar x)1119 Scalar SpecFunc::Erf(const Scalar x)
1120 {
1121   return Faddeeva::erf(x);
1122 }
1123 
Erf(const Complex & z)1124 Complex SpecFunc::Erf(const Complex & z)
1125 {
1126   return Faddeeva::erf(z);
1127 }
1128 
1129 // Erf function ErfI(x) = -i.erf(ix)
ErfI(const Scalar x)1130 Scalar SpecFunc::ErfI(const Scalar x)
1131 {
1132   return Faddeeva::erfi(x);
1133 }
1134 
ErfI(const Complex & z)1135 Complex SpecFunc::ErfI(const Complex & z)
1136 {
1137   return Faddeeva::erfi(z);
1138 }
1139 
1140 // Erf function ErfC(x) = 1 - Erf(x)
ErfC(const Scalar x)1141 Scalar SpecFunc::ErfC(const Scalar x)
1142 {
1143   return Faddeeva::erfc(x);
1144 }
1145 
ErfC(const Complex & z)1146 Complex SpecFunc::ErfC(const Complex & z)
1147 {
1148   return Faddeeva::erfc(z);
1149 }
1150 
1151 // Erf function ErfCX(x) = exp(x^2).erfC(x)
ErfCX(const Scalar x)1152 Scalar SpecFunc::ErfCX(const Scalar x)
1153 {
1154   return Faddeeva::erfcx(x);
1155 }
1156 
ErfCX(const Complex & z)1157 Complex SpecFunc::ErfCX(const Complex & z)
1158 {
1159   return Faddeeva::erfcx(z);
1160 }
1161 
1162 // Inverse of the Erf function
1163 // We use a rational approximation followed by one Halley's iteration (higher order Newton iteration)
ErfInverse(const Scalar x)1164 Scalar SpecFunc::ErfInverse(const Scalar x)
1165 {
1166   Scalar p = 0.5 * (x + 1.0);
1167   static const Scalar a[6] =
1168   {
1169     -3.969683028665376e+01,  2.209460984245205e+02,
1170       -2.759285104469687e+02,  1.383577518672690e+02,
1171       -3.066479806614716e+01,  2.506628277459239e+00
1172     };
1173   static const Scalar b[5] =
1174   {
1175     -5.447609879822406e+01,  1.615858368580409e+02,
1176       -1.556989798598866e+02,  6.680131188771972e+01,
1177       -1.328068155288572e+01
1178     };
1179   static const Scalar c[6] =
1180   {
1181     -7.784894002430293e-03, -3.223964580411365e-01,
1182       -2.400758277161838e+00, -2.549732539343734e+00,
1183       4.374664141464968e+00,  2.938163982698783e+00
1184     };
1185   static const Scalar d[4] =
1186   {
1187     7.784695709041462e-03,  3.224671290700398e-01,
1188     2.445134137142996e+00,  3.754408661907416e+00
1189   };
1190   Scalar q = -1.0;
1191   Scalar t = -1.0;
1192   Scalar u = -1.0;
1193   q = std::min(p, 1.0 - p);
1194   if (q > 0.02425)
1195   {
1196     /* Rational approximation for central region. */
1197     u = q - 0.5;
1198     t = u * u;
1199     u = u * (((((a[0] * t + a[1]) * t + a[2]) * t + a[3]) * t + a[4]) * t + a[5])
1200         / (((((b[0] * t + b[1]) * t + b[2]) * t + b[3]) * t + b[4]) * t + 1.0);
1201   }
1202   else
1203   {
1204     /* Rational approximation for tail region. */
1205     t = sqrt(-2.0 * std::log(q));
1206     u = (((((c[0] * t + c[1]) * t + c[2]) * t + c[3]) * t + c[4]) * t + c[5])
1207         / ((((d[0] * t + d[1]) * t + d[2]) * t + d[3]) * t + 1.0);
1208   }
1209   /* The relative error of the approximation has absolute value less
1210      than 1.15e-9.  One iteration of Halley's rational method (third
1211      order) gives full machine precision... */
1212   t = 0.5 + 0.5 * Erf(u * M_SQRT1_2) - q;    /* f(u) = error */
1213   // 2.50662827463100050241576528481 = sqrt(2.pi)
1214   t = t * 2.50662827463100050241576528481 * std::exp(0.5 * u * u);   /* f(u)/df(u) */
1215   u = u - t / (1.0 + 0.5 * u * t);     /* Halley's method */
1216   return (p > 0.5 ? -M_SQRT1_2 * u : M_SQRT1_2 * u);
1217 }
1218 
1219 /* Evaluation of the principal branch of Lambert W function.
1220    Based on formulas exposed in:
1221    Robert M. Corless, G. H. Gonnet, D. E. G. Hare, D. J. Jeffrey, and D. E. Knuth, "On the Lambert W Function", Advances in Computational Mathematics, volume 5, 1996, pp. 329--359
1222 */
LambertW(const Scalar x,const Bool principal)1223 Scalar SpecFunc::LambertW(const Scalar x,
1224                           const Bool principal)
1225 {
1226   Scalar w = -1.0;
1227   // -0.36787944117144232159552377016146086 = -1 / exp(1)
1228   if (x <= -0.3678794411714423215955238) return w;
1229   // Principal branch, defined over [-1/e,+inf], LambertW >= -1
1230   if (principal)
1231   {
1232     if (x == 0) return 0.0;
1233     if(x < 6.46) w = x * (3.0 + 4.0 * x) / (3.0 + x * (7.0 + 2.5 * x));
1234     // Large argument, use asymptotic expansion, formula 4.18
1235     else
1236     {
1237       const Scalar t1 = std::log(x);
1238       w = t1 - std::log(t1);
1239     }
1240   }
1241   // Second real branch, defined over [-1/e, 0[, LambertW <= -1
1242   else
1243   {
1244     if (x >= 0.0) return - std::numeric_limits<Scalar>::infinity();
1245     if (x < -0.1) w = -2.0;
1246     else
1247     {
1248       const Scalar t1 = std::log(-x);
1249       w = t1 - std::log(-t1);
1250     }
1251   }
1252   // Halley's iteration
1253   for (UnsignedInteger i = 0; i < 3; ++i)
1254   {
1255     const Scalar expW = std::exp(w);
1256     const Scalar numerator = w * expW - x;
1257     const Scalar dw = numerator / (expW * (w + 1.0) - 0.5 * (w + 2.0) * numerator / (w + 1.0));
1258     w -= dw;
1259   }
1260   return w;
1261 }
1262 
1263 // Accurate evaluation of log(1+z) for |z|<<1
Log1p(const Complex & z)1264 Complex SpecFunc::Log1p(const Complex & z)
1265 {
1266   if (std::norm(z) < 1e-5) return z * (1.0 + z * (-0.5 + z / 3.0));
1267   return std::log(1.0 + z);
1268 }
1269 
1270 // Accurate evaluation of exp(z)-1 for |z|<<1
Expm1(const Complex & z)1271 Complex SpecFunc::Expm1(const Complex & z)
1272 {
1273   if (std::norm(z) < 1e-5) return z * (1.0 + 0.5 * z * (1.0 + z / 3.0));
1274   return std::exp(z) - 1.0;
1275 }
1276 
1277 // Accurate evaluation of log(1-exp(-x)) for all x > 0
Log1MExp(const Scalar x)1278 Complex SpecFunc::Log1MExp(const Scalar x)
1279 {
1280   if (!(x > 0.0)) throw InvalidArgumentException(HERE) << "Error: x must be positive";
1281   if (x <= M_LN2) return std::log(-expm1(-x));
1282   return log1p(-std::exp(-x));
1283 }
1284 
1285 // Integer log2
Log2(const Unsigned64BitsInteger n)1286 UnsignedInteger SpecFunc::Log2(const Unsigned64BitsInteger n)
1287 {
1288   if (!(n > 0)) throw InvalidArgumentException(HERE) << "Error: n must be positive";
1289 
1290   // De Bruijn sequence
1291   const UnsignedInteger tab64[64] =
1292   {
1293     63,  0, 58,  1, 59, 47, 53,  2,
1294     60, 39, 48, 27, 54, 33, 42,  3,
1295     61, 51, 37, 40, 49, 18, 28, 20,
1296     55, 30, 34, 11, 43, 14, 22,  4,
1297     62, 57, 46, 52, 38, 26, 32, 41,
1298     50, 36, 17, 19, 29, 10, 13, 21,
1299     56, 45, 25, 31, 35, 16,  9, 12,
1300     44, 24, 15,  8, 23,  7,  6,  5
1301   };
1302 
1303   // http://www.pearsonhighered.com/samplechapter/0201914654.pdf
1304   Unsigned64BitsInteger value = n;
1305   value |= value >> 1;
1306   value |= value >> 2;
1307   value |= value >> 4;
1308   value |= value >> 8;
1309   value |= value >> 16;
1310   value |= value >> 32;
1311 
1312   return tab64[((Unsigned64BitsInteger)((value - (value >> 1)) * 0x07EDD5E59A4E28C2)) >> 58];
1313 }
1314 
1315 // Compute the smallest power of two greater or equal to the given n
NextPowerOfTwo(const UnsignedInteger n)1316 UnsignedInteger SpecFunc::NextPowerOfTwo(const UnsignedInteger n)
1317 {
1318   UnsignedInteger powerOfTwo = 1;
1319   while (powerOfTwo < n) powerOfTwo <<= 1;
1320   return powerOfTwo;
1321 }
1322 
1323 // Integer power
IPow(const Scalar x,const SignedInteger n)1324 Scalar SpecFunc::IPow(const Scalar x, const SignedInteger n)
1325 {
1326   if (n == 0) return 1.0;
1327   if (x == 0) return 0.0;
1328   if (x < 0.0)
1329   {
1330     if (n % 2) return -std::pow(-x, 1.0 * n);
1331     return std::pow(-x, 1.0 * n);
1332   }
1333   return std::pow(x, 1.0 * n);
1334 }
1335 
1336 // Integer root
IRoot(const Scalar x,const SignedInteger n)1337 Scalar SpecFunc::IRoot(const Scalar x, const SignedInteger n)
1338 {
1339   if (n == 0) throw InvalidArgumentException(HERE) << "Cannot take the zeroth root of anything!";
1340   if (x == 0) return 0.0;
1341   if (x < 0.0)
1342   {
1343     if (n % 2 == 0) throw InvalidArgumentException(HERE) << "Cannot take an even root of a negative number";
1344     return -std::pow(-x, 1.0 / n);
1345   }
1346   return std::pow(x, 1.0 / n);
1347 }
1348 
1349 
1350 // Compute the number of bits sets to 1 in n
1351 // Best known algorithm for 64 bits n and fast multiply
BitCount(const Unsigned64BitsInteger n)1352 UnsignedInteger SpecFunc::BitCount(const Unsigned64BitsInteger n)
1353 {
1354   // types and constants used in the functions below
1355 
1356   const Unsigned64BitsInteger m1 = 0x5555555555555555; //binary: 0101...
1357   const Unsigned64BitsInteger m2 = 0x3333333333333333; //binary: 00110011..
1358   const Unsigned64BitsInteger m4 = 0x0f0f0f0f0f0f0f0f; //binary:  4 zeros,  4 ones ...
1359   const Unsigned64BitsInteger h01 = 0x0101010101010101; //the sum of 256 to the power of 0,1,2,3...
1360 
1361   // This uses fewer arithmetic operations than any other known
1362   // implementation on machines with fast multiplication.
1363   // It uses 12 arithmetic operations, one of which is a multiply.
1364   Unsigned64BitsInteger x = n;
1365   x -= (x >> 1) & m1;             // put count of each 2 bits into those 2 bits
1366   x = (x & m2) + ((x >> 2) & m2); // put count of each 4 bits into those 4 bits
1367   x = (x + (x >> 4)) & m4;        // put count of each 8 bits into those 8 bits
1368   return (x * h01) >> 56;         // returns left 8 bits of x + (x << 8) + (x << 16) + (x << 24) + ...
1369 }
1370 
1371 // Missing functions in cmath wrt math.h as of C++98
Acosh(const Scalar x)1372 Scalar SpecFunc::Acosh(const Scalar x)
1373 {
1374   if (!(x >= 1.0)) throw InvalidArgumentException(HERE) << "Error: acosh is only defined for x>=1, here x=" << x;
1375   return 2.0 * std::log(sqrt(0.5 * (x + 1.0)) + sqrt(0.5 * (x - 1.0)));
1376 }
1377 
Asinh(const Scalar x)1378 Scalar SpecFunc::Asinh(const Scalar x)
1379 {
1380   if (std::abs(x) < 0.0081972522783123062436) return x * (1.0 + x * x * (-1.0 / 6.0 + 3.0 * x * x / 40.0));
1381   return std::log(x + sqrt(1.0 + x * x));
1382 }
1383 
Atanh(const Scalar x)1384 Scalar SpecFunc::Atanh(const Scalar x)
1385 {
1386   if (std::abs(x) < 0.0069422277258991260322) return x * (1.0 + x * x * (1.0 / 3.0 + x * x / 5.0));
1387   if (x > 0.0) return 0.5 * log1p(2.0 * x / (1.0 - x));
1388   return -0.5 * log1p(-2.0 * x / (1.0 + x));
1389 }
1390 
Cbrt(const Scalar x)1391 Scalar SpecFunc::Cbrt(const Scalar x)
1392 {
1393   if (x == 0.0) return 0.0;
1394   return (x < 0.0 ? -std::exp(std::log(-x) / 3.0) : std::exp(std::log(x) / 3.0));
1395 }
1396 
BinomialCoefficient(const UnsignedInteger n,const UnsignedInteger k)1397 UnsignedInteger SpecFunc::BinomialCoefficient(const UnsignedInteger n,
1398     const UnsignedInteger k)
1399 {
1400   if (k > n) return 0; // by convention
1401   UnsignedInteger value = 1;
1402   for (UnsignedInteger i = 0; i < std::min(k, n - k); ++ i)
1403   {
1404     value *= n - i;
1405     value /= i + 1;
1406   }
1407   return value;
1408 }
1409 
1410 
1411 END_NAMESPACE_OPENTURNS
1412