igam.c
Go to the documentation of this file.
1 /* igam.c
2  *
3  * Incomplete Gamma integral
4  *
5  *
6  *
7  * SYNOPSIS:
8  *
9  * double a, x, y, igam();
10  *
11  * y = igam( a, x );
12  *
13  * DESCRIPTION:
14  *
15  * The function is defined by
16  *
17  * x
18  * -
19  * 1 | | -t a-1
20  * igam(a,x) = ----- | e t dt.
21  * - | |
22  * | (a) -
23  * 0
24  *
25  *
26  * In this implementation both arguments must be positive.
27  * The integral is evaluated by either a power series or
28  * continued fraction expansion, depending on the relative
29  * values of a and x.
30  *
31  * ACCURACY:
32  *
33  * Relative error:
34  * arithmetic domain # trials peak rms
35  * IEEE 0,30 200000 3.6e-14 2.9e-15
36  * IEEE 0,100 300000 9.9e-14 1.5e-14
37  */
38  /* igamc()
39  *
40  * Complemented incomplete Gamma integral
41  *
42  *
43  *
44  * SYNOPSIS:
45  *
46  * double a, x, y, igamc();
47  *
48  * y = igamc( a, x );
49  *
50  * DESCRIPTION:
51  *
52  * The function is defined by
53  *
54  *
55  * igamc(a,x) = 1 - igam(a,x)
56  *
57  * inf.
58  * -
59  * 1 | | -t a-1
60  * = ----- | e t dt.
61  * - | |
62  * | (a) -
63  * x
64  *
65  *
66  * In this implementation both arguments must be positive.
67  * The integral is evaluated by either a power series or
68  * continued fraction expansion, depending on the relative
69  * values of a and x.
70  *
71  * ACCURACY:
72  *
73  * Tested at random a, x.
74  * a x Relative error:
75  * arithmetic domain domain # trials peak rms
76  * IEEE 0.5,100 0,100 200000 1.9e-14 1.7e-15
77  * IEEE 0.01,0.5 0,100 200000 1.4e-13 1.6e-15
78  */
79 
80 /*
81  * Cephes Math Library Release 2.0: April, 1987
82  * Copyright 1985, 1987 by Stephen L. Moshier
83  * Direct inquiries to 30 Frost Street, Cambridge, MA 02140
84  */
85 
86 /* Sources
87  * [1] "The Digital Library of Mathematical Functions", dlmf.nist.gov
88  * [2] Maddock et. al., "Incomplete Gamma Functions",
89  * https://www.boost.org/doc/libs/1_61_0/libs/math/doc/html/math_toolkit/sf_gamma/igamma.html
90  */
91 
92 /* Scipy changes:
93  * - 05-01-2016: added asymptotic expansion for igam to improve the
94  * a ~ x regime.
95  * - 06-19-2016: additional series expansion added for igamc to
96  * improve accuracy at small arguments.
97  * - 06-24-2016: better choice of domain for the asymptotic series;
98  * improvements in accuracy for the asymptotic series when a and x
99  * are very close.
100  */
101 
102 #include "mconf.h"
103 #include "lanczos.h"
104 #include "igam.h"
105 
106 #ifdef MAXITER
107 #undef MAXITER
108 #endif
109 
110 #define MAXITER 2000
111 #define IGAM 1
112 #define IGAMC 0
113 #define SMALL 20
114 #define LARGE 200
115 #define SMALLRATIO 0.3
116 #define LARGERATIO 4.5
117 
118 extern double MACHEP, MAXLOG;
119 static double big = 4.503599627370496e15;
120 static double biginv = 2.22044604925031308085e-16;
121 
122 static double igamc_continued_fraction(double, double);
123 static double igam_series(double, double);
124 static double igamc_series(double, double);
125 static double asymptotic_series(double, double, int);
126 
127 
128 double igam(double a, double x)
129 {
130  double absxma_a;
131 
132  if (x < 0 || a < 0) {
133  sf_error("gammainc", SF_ERROR_DOMAIN, NULL);
134  return NAN;
135  } else if (a == 0) {
136  if (x > 0) {
137  return 1;
138  } else {
139  return NAN;
140  }
141  } else if (x == 0) {
142  /* Zero integration limit */
143  return 0;
144  } else if (isinf(a)) {
145  if (isinf(x)) {
146  return NAN;
147  }
148  return 0;
149  } else if (isinf(x)) {
150  return 1;
151  }
152 
153  /* Asymptotic regime where a ~ x; see [2]. */
154  absxma_a = fabs(x - a) / a;
155  if ((a > SMALL) && (a < LARGE) && (absxma_a < SMALLRATIO)) {
156  return asymptotic_series(a, x, IGAM);
157  } else if ((a > LARGE) && (absxma_a < LARGERATIO / sqrt(a))) {
158  return asymptotic_series(a, x, IGAM);
159  }
160 
161  if ((x > 1.0) && (x > a)) {
162  return (1.0 - igamc(a, x));
163  }
164 
165  return igam_series(a, x);
166 }
167 
168 
169 double igamc(double a, double x)
170 {
171  double absxma_a;
172 
173  if (x < 0 || a < 0) {
174  sf_error("gammaincc", SF_ERROR_DOMAIN, NULL);
175  return NAN;
176  } else if (a == 0) {
177  if (x > 0) {
178  return 0;
179  } else {
180  return NAN;
181  }
182  } else if (x == 0) {
183  return 1;
184  } else if (isinf(a)) {
185  if (isinf(x)) {
186  return NAN;
187  }
188  return 1;
189  } else if (isinf(x)) {
190  return 0;
191  }
192 
193  /* Asymptotic regime where a ~ x; see [2]. */
194  absxma_a = fabs(x - a) / a;
195  if ((a > SMALL) && (a < LARGE) && (absxma_a < SMALLRATIO)) {
196  return asymptotic_series(a, x, IGAMC);
197  } else if ((a > LARGE) && (absxma_a < LARGERATIO / sqrt(a))) {
198  return asymptotic_series(a, x, IGAMC);
199  }
200 
201  /* Everywhere else; see [2]. */
202  if (x > 1.1) {
203  if (x < a) {
204  return 1.0 - igam_series(a, x);
205  } else {
206  return igamc_continued_fraction(a, x);
207  }
208  } else if (x <= 0.5) {
209  if (-0.4 / log(x) < a) {
210  return 1.0 - igam_series(a, x);
211  } else {
212  return igamc_series(a, x);
213  }
214  } else {
215  if (x * 1.1 < a) {
216  return 1.0 - igam_series(a, x);
217  } else {
218  return igamc_series(a, x);
219  }
220  }
221 }
222 
223 
224 /* Compute
225  *
226  * x^a * exp(-x) / gamma(a)
227  *
228  * corrected from (15) and (16) in [2] by replacing exp(x - a) with
229  * exp(a - x).
230  */
231 double igam_fac(double a, double x)
232 {
233  double ax, fac, res, num;
234 
235  if (fabs(a - x) > 0.4 * fabs(a)) {
236  ax = a * log(x) - x - lgam(a);
237  if (ax < -MAXLOG) {
238  sf_error("igam", SF_ERROR_UNDERFLOW, NULL);
239  return 0.0;
240  }
241  return exp(ax);
242  }
243 
244  fac = a + lanczos_g - 0.5;
245  res = sqrt(fac / exp(1)) / lanczos_sum_expg_scaled(a);
246 
247  if ((a < 200) && (x < 200)) {
248  res *= exp(a - x) * pow(x / fac, a);
249  } else {
250  num = x - a - lanczos_g + 0.5;
251  res *= exp(a * log1pmx(num / fac) + x * (0.5 - lanczos_g) / fac);
252  }
253 
254  return res;
255 }
256 
257 
258 /* Compute igamc using DLMF 8.9.2. */
259 static double igamc_continued_fraction(double a, double x)
260 {
261  int i;
262  double ans, ax, c, yc, r, t, y, z;
263  double pk, pkm1, pkm2, qk, qkm1, qkm2;
264 
265  ax = igam_fac(a, x);
266  if (ax == 0.0) {
267  return 0.0;
268  }
269 
270  /* continued fraction */
271  y = 1.0 - a;
272  z = x + y + 1.0;
273  c = 0.0;
274  pkm2 = 1.0;
275  qkm2 = x;
276  pkm1 = x + 1.0;
277  qkm1 = z * x;
278  ans = pkm1 / qkm1;
279 
280  for (i = 0; i < MAXITER; i++) {
281  c += 1.0;
282  y += 1.0;
283  z += 2.0;
284  yc = y * c;
285  pk = pkm1 * z - pkm2 * yc;
286  qk = qkm1 * z - qkm2 * yc;
287  if (qk != 0) {
288  r = pk / qk;
289  t = fabs((ans - r) / r);
290  ans = r;
291  }
292  else
293  t = 1.0;
294  pkm2 = pkm1;
295  pkm1 = pk;
296  qkm2 = qkm1;
297  qkm1 = qk;
298  if (fabs(pk) > big) {
299  pkm2 *= biginv;
300  pkm1 *= biginv;
301  qkm2 *= biginv;
302  qkm1 *= biginv;
303  }
304  if (t <= MACHEP) {
305  break;
306  }
307  }
308 
309  return (ans * ax);
310 }
311 
312 
313 /* Compute igam using DLMF 8.11.4. */
314 static double igam_series(double a, double x)
315 {
316  int i;
317  double ans, ax, c, r;
318 
319  ax = igam_fac(a, x);
320  if (ax == 0.0) {
321  return 0.0;
322  }
323 
324  /* power series */
325  r = a;
326  c = 1.0;
327  ans = 1.0;
328 
329  for (i = 0; i < MAXITER; i++) {
330  r += 1.0;
331  c *= x / r;
332  ans += c;
333  if (c <= MACHEP * ans) {
334  break;
335  }
336  }
337 
338  return (ans * ax / a);
339 }
340 
341 
342 /* Compute igamc using DLMF 8.7.3. This is related to the series in
343  * igam_series but extra care is taken to avoid cancellation.
344  */
345 static double igamc_series(double a, double x)
346 {
347  int n;
348  double fac = 1;
349  double sum = 0;
350  double term, logx;
351 
352  for (n = 1; n < MAXITER; n++) {
353  fac *= -x / n;
354  term = fac / (a + n);
355  sum += term;
356  if (fabs(term) <= MACHEP * fabs(sum)) {
357  break;
358  }
359  }
360 
361  logx = log(x);
362  term = -expm1(a * logx - lgam1p(a));
363  return term - exp(a * logx - lgam(a)) * sum;
364 }
365 
366 
367 /* Compute igam/igamc using DLMF 8.12.3/8.12.4. */
368 static double asymptotic_series(double a, double x, int func)
369 {
370  int k, n, sgn;
371  int maxpow = 0;
372  double lambda = x / a;
373  double sigma = (x - a) / a;
374  double eta, res, ck, ckterm, term, absterm;
375  double absoldterm = INFINITY;
376  double etapow[N] = {1};
377  double sum = 0;
378  double afac = 1;
379 
380  if (func == IGAM) {
381  sgn = -1;
382  } else {
383  sgn = 1;
384  }
385 
386  if (lambda > 1) {
387  eta = sqrt(-2 * log1pmx(sigma));
388  } else if (lambda < 1) {
389  eta = -sqrt(-2 * log1pmx(sigma));
390  } else {
391  eta = 0;
392  }
393  res = 0.5 * erfc(sgn * eta * sqrt(a / 2));
394 
395  for (k = 0; k < K; k++) {
396  ck = d[k][0];
397  for (n = 1; n < N; n++) {
398  if (n > maxpow) {
399  etapow[n] = eta * etapow[n-1];
400  maxpow += 1;
401  }
402  ckterm = d[k][n]*etapow[n];
403  ck += ckterm;
404  if (fabs(ckterm) < MACHEP * fabs(ck)) {
405  break;
406  }
407  }
408  term = ck * afac;
409  absterm = fabs(term);
410  if (absterm > absoldterm) {
411  break;
412  }
413  sum += term;
414  if (absterm < MACHEP * fabs(sum)) {
415  break;
416  }
417  absoldterm = absterm;
418  afac /= a;
419  }
420  res += sgn * exp(-0.5 * a * eta * eta) * sum / sqrt(2 * M_PI * a);
421 
422  return res;
423 }
igam_series
static double igam_series(double, double)
Definition: igam.c:314
lgam1p
double lgam1p(double x)
Definition: unity.c:181
igamc
double igamc(double a, double x)
Definition: igam.c:169
MAXITER
#define MAXITER
Definition: igam.c:110
d
static const double d[K][N]
Definition: igam.h:11
c
Scalar Scalar * c
Definition: benchVecAdd.cpp:17
x
set noclip points set clip one set noclip two set bar set border lt lw set xdata set ydata set zdata set x2data set y2data set boxwidth set dummy x
Definition: gnuplot_common_settings.hh:12
igam
double igam(double a, double x)
Definition: igam.c:128
log
const EIGEN_DEVICE_FUNC LogReturnType log() const
Definition: ArrayCwiseUnaryOps.h:128
res
cout<< "Here is the matrix m:"<< endl<< m<< endl;Matrix< ptrdiff_t, 3, 1 > res
Definition: PartialRedux_count.cpp:3
exp
const EIGEN_DEVICE_FUNC ExpReturnType exp() const
Definition: ArrayCwiseUnaryOps.h:97
IGAMC
#define IGAMC
Definition: igam.c:112
lgam
double lgam(double x)
Definition: gamma.c:275
asymptotic_series
static double asymptotic_series(double, double, int)
Definition: igam.c:368
sampling::sigma
static const double sigma
Definition: testGaussianBayesNet.cpp:170
boost::multiprecision::fabs
Real fabs(const Real &a)
Definition: boostmultiprec.cpp:119
SF_ERROR_UNDERFLOW
@ SF_ERROR_UNDERFLOW
Definition: sf_error.h:11
n
int n
Definition: BiCGSTAB_simple.cpp:1
IGAM
#define IGAM
Definition: igam.c:111
expm1
double expm1(double x)
Definition: unity.c:106
igam_fac
double igam_fac(double a, double x)
Definition: igam.c:231
igamc_continued_fraction
static double igamc_continued_fraction(double, double)
Definition: igam.c:259
lanczos.h
biginv
static double biginv
Definition: igam.c:120
pybind_wrapper_test_script.z
z
Definition: pybind_wrapper_test_script.py:61
MACHEP
double MACHEP
Definition: const.c:54
lanczos_sum_expg_scaled
double lanczos_sum_expg_scaled(double x)
Definition: lanczos.c:25
lambda
static double lambda[]
Definition: jv.c:524
y
Scalar * y
Definition: level1_cplx_impl.h:124
Eigen::ArrayBase::pow
const Eigen::CwiseBinaryOp< Eigen::internal::scalar_pow_op< typename Derived::Scalar, typename ExponentDerived::Scalar >, const Derived, const ExponentDerived > pow(const Eigen::ArrayBase< Derived > &x, const Eigen::ArrayBase< ExponentDerived > &exponents)
Definition: GlobalFunctions.h:143
a
ArrayXXi a
Definition: Array_initializer_list_23_cxx11.cpp:1
mconf.h
K
#define K
Definition: igam.h:8
big
static double big
Definition: igam.c:119
sf_error
void sf_error(const char *func_name, sf_error_t code, const char *fmt,...)
Definition: sf_error.c:41
igam.h
SMALL
#define SMALL
Definition: igam.c:113
MAXLOG
double MAXLOG
Definition: igam.c:118
N
#define N
Definition: igam.h:9
NULL
#define NULL
Definition: ccolamd.c:609
log1pmx
double log1pmx(double x)
Definition: unity.c:63
M_PI
#define M_PI
Definition: mconf.h:117
erfc
double erfc(double a)
Definition: ndtr.c:227
func
Definition: benchGeometry.cpp:23
align_3::t
Point2 t(10, 10)
SF_ERROR_DOMAIN
@ SF_ERROR_DOMAIN
Definition: sf_error.h:16
igamc_series
static double igamc_series(double, double)
Definition: igam.c:345
ceres::sqrt
Jet< T, N > sqrt(const Jet< T, N > &f)
Definition: jet.h:418
i
int i
Definition: BiCGSTAB_step_by_step.cpp:9
SMALLRATIO
#define SMALLRATIO
Definition: igam.c:115
LARGE
#define LARGE
Definition: igam.c:114
isinf
#define isinf(X)
Definition: main.h:94
lanczos_g
static const double lanczos_g
Definition: lanczos.h:131
LARGERATIO
#define LARGERATIO
Definition: igam.c:116


gtsam
Author(s):
autogenerated on Sat Nov 16 2024 04:02:27