STK++ 0.9.13
STK_Funct_betaRatio.cpp
Go to the documentation of this file.
1/*--------------------------------------------------------------------*/
2/* Copyright (C) 2004-2016 Serge Iovleff, Université Lille 1, Inria
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this program; if not, write to the
16 Free Software Foundation, Inc.,
17 59 Temple Place,
18 Suite 330,
19 Boston, MA 02111-1307
20 USA
21
22 Contact : S..._Dot_I..._At_stkpp_Dot_org (see copyright for ...)
23*/
24
25/*
26 * Project: Analysis
27 * Purpose: Implementation of functions around the beta function ratio
28 * Author: Serge Iovleff, S..._Dot_I..._At_stkpp_Dot_org (see copyright for ...)
29 **/
30
35#ifndef IS_RTKPP_LIBRARY
36
37#include "../include/STK_Funct_betaRatio.h"
38#include "../include/STK_Funct_gammaRatio.h"
39#include "../include/STK_Funct_raw.h"
40
41
42#define d1(z) (0.5)
43#define d2(z) (z/8. - 0.05)
44#define d3(z) (z*(z/48.-1./40.)+1./105.)
45#define d4(z) (z*(z*(z/384.-1./160.)+101./16800.)-3./1400.)
46#define d5(z) (z*(z*(z*(z/3840.-1./960.)+61./33600.)-13./8400.) \
47 +1./1925.)
48#define d6(z) (z*(z*(z*(z*(z/46080.-1./7680.)+143./403200.) \
49 -59./112000.)+7999./19404000.)-691./5255250.)
50#define d7(z) (z*(z*(z*(z*(z*(z/645120.-1./76800.)+41./806400.) \
51 -11./96000.)+5941./38808000.)-2357./21021000.)+6./175175.)
52#define d8(z) (z*(z*(z*(z*(z*(z*(z/10321920.-1./921600.)+37./6451200.) \
53 -73./4032000.)+224137./6209280000.)-449747./10090080000.) \
54 +52037./1681680000.)-10851./1191190000.)
55
56
57namespace STK
58{
59
60namespace Funct
61{
62
75Real betaRatio_ae( Real const& a, Real const& b, Real const& x
76 , bool xm1, bool lower_tail
77 )
78{
79#ifdef STK_BETARATIO_DEBUG
80 stk_cout << _T("BetaRatio_ae(") << a << _T(", ") << b << _T(", ") << x << _T(")\n");
81#endif
82 // Compute b-1
83 Real bm1 = b-1;
84 // compute \nu = a+(b-1)/2
85 Real nu = a+bm1/2.;
86 // compute D = -\nu*log(x)
87 Real D = (xm1 ? -log1p(-x) : -log(x)) * nu;
88 // check trivial case
89 if (D == 0.) return lower_tail ? 1. : 0.;
90 if (Arithmetic<Real>::isInfinite(D)) return lower_tail ? 0. : 1.;
91 // compute 12*\nu^2
92 nu *= 12*nu;
93 // variables for the series
94 Real term = 1.;
95 Real ak_term = 1.;
96 Real a_k = 1.;
97 // numerator and denominator
98 Real den = term;
99 Real num = 0.;
100 // update term
101 term *= bm1;
102 // Generalized bernouilli coefs
103 // coef 1 (d_1 = 1/2)
104 term *= (b)*(b+1)/nu;
105 Real coef = term/2; // d_1 = 1/2
106 den += coef;
107 a_k += (ak_term *= D/(b+1));
108 num += coef * a_k;
109 // coef 2
110 term *= (b+2)*(b+3)/nu;
111 coef = d2(bm1)*term;
112 den += coef;
113 a_k += (ak_term *= D/(b+2));
114 a_k += (ak_term *= D/(b+3));
115 num += coef * a_k;
116 // coef 3
117 term *= (b+4)*(b+5)/nu;
118 coef = d3(bm1)*term;
119 den += coef;
120 a_k += (ak_term *= D/(b+4));
121 a_k += (ak_term *= D/(b+5));
122 num += coef * a_k;
123 // coef 4
124 term *= (b+6)*(b+7)/nu;
125 coef = d4(bm1)*term;
126 den += coef;
127 a_k += (ak_term *= D/(b+6));
128 a_k += (ak_term *= D/(b+7));
129 num += coef * a_k;
130 // coef 5
131 term *= (b+8)*(b+9)/nu;
132 coef = d5(bm1)*term;
133 den += coef;
134 a_k += (ak_term *= D/(b+8));
135 a_k += (ak_term *= D/(b+9));
136 num += coef * a_k;
137 // coef 6
138 term *= (b+10)*(b+11)/nu;
139 coef = d6(bm1)*term;
140 den += coef;
141 a_k += (ak_term *= D/(b+10));
142 a_k += (ak_term *= D/(b+11));
143 num += coef * a_k;
144 // coef 7
145 term *= (b+12)*(b+13)/nu;
146 coef = d7(bm1)*term;
147 den += coef;
148 a_k += (ak_term *= D/(b+12));
149 a_k += (ak_term *= D/(b+13));
150 num += coef * a_k;
151 // coef 8
152 term *= (b+14)*(b+15)/nu;
153 coef = d8(bm1)*term;
154 den += coef;
155 a_k += (ak_term *= D/(b+14));
156 a_k += (ak_term *= D/(b+15));
157 num += coef * a_k;
158 // result (P or Q ?)
159 return lower_tail ? gammaRatioQ(b, D)
160 + (num / den) * poisson_pdf_raw(b, D)
161 : gammaRatioP(b, D)
162 - (num / den) * poisson_pdf_raw(b, D);
163}
164
180Real betaRatio_sr( Real const& a, Real const& b, Real x
181 , bool xm1, bool lower_tail
182 )
183{
184#ifdef STK_BETARATIO_DEBUG
185 stk_cout << _T("BetaRatio_sr(") << a << _T(", ") << b << _T(", ") << x << _T(")\n");
186#endif
187 // constants
188 Real s = a+b, sx = s*x, sy = s*(1-x);
189 // compute B(a,b,x,y) = \frac{\Gamma(a+b)}{\Gamma(a) \Gamma(b)} x^{a}
190 Real bt = ( Const::_1_SQRT2PI_*sqrt((a*b)/s)
191 * exp( ( lgammaStirlingError(s)
193 )
194 + (xm1 ? sy- (dev0(a, sy) + dev0(b, s)) : sx- (dev0(a, sx) + dev0(b, s)))
195 )
196 );
197 Real y = (0.5 - x) + 0.5;
198 if (xm1) std::swap(x,y);
199 // check factor
200 if (!bt) return lower_tail ? 0. : 1.;
201 // parameters
202 int n = 1;
203 Real sum = 0.0, c= 1., term;
204 do
205 {
206 sum += (term = (c *= (1.-b/n)*x) / (a+n));
207 ++n;
208 }
209 while (std::abs(term) > std::abs(sum) * Arithmetic<Real>::epsilon());
210 // return result
211 return lower_tail ? bt*(1./a + sum) : (1.-bt/a-bt*sum);
212}
213
229static Real serie_up( Real const& a, Real const& b, Real x, bool xm1, int n)
230{
231 // trivial case
232 if (n==1) return b1(a, b, x, xm1)/a;
233
234 // constants
235 Real s = a+b, sx=s*x, sy = s- sx;
236 Real x0 = (xm1) ? (0.5 -x) + 0.5 : x;
237 int l = std::min(std::max(0, (int)round( xm1 ? (sy-a+1)/x : (sx-a+1)/x0)), n-1);
238 Real sum1 = 0., sum2 = 1., s0 = s+l, a0 = a+l;
239 // first serie
240 for (int k=n-l-2; k>=0; --k) { sum2 = 1. + sum2 *x0*(s0+k)/(a0+k+1);}
241 // second serie
242 if (l>0)
243 {
244 sum1 = 1.;
245 for (int k=1; k<l; ++k) { sum1 = 1.+ sum1*(a+k)/((s+k-1)*x0);}
246 sum1 /= ((s0-1)*x0);
247 }
248 // return result
249 return b1(a+l, b, x, xm1) *(sum2/a0 + sum1);
250}
251
264Real betaRatio_up( Real const& a, Real const& b, Real const& x
265 , bool xm1, bool lower_tail
266 )
267{
268#ifdef STK_BETARATIO_DEBUG
269 stk_cout << _T("BetaRatio_up(") << a << _T(", ") << b << _T(", ") << x << _T(")\n");
270#endif
271 // number of iterations
272 int n = int(a);
273 // compute residual
274 Real a0 = a-n;
275 // zero case
276 if (!a0) { --n; a0=1.;}
277 // sum
278 Real c= serie_up(a0, b, x, xm1, n) * (lower_tail ? - 1. : 1.);
279 return (b<=15) ? betaRatio_sr(a0, b, x, xm1, lower_tail) +c
280 : betaRatio_ae(b, a0, x, !xm1, !lower_tail) +c;
281}
282
302Real betaRatio_cf( Real const& a, Real const& b, Real x
303 , bool xm1, bool lower_tail
304 )
305{
306#ifdef STK_BETARATIO_DEBUG
307 stk_cout << _T("BetaRatio_cf(") << a << _T(", ") << b << _T(", ") << x << _T(")\n");
308#endif
309 // parameters
310 Real s = a+b, sx = s*x, sy = s-sx;
311 /* Compute the function:
312 * B(a,b,x,y) = \frac{ x^{a} (1-x)^{b}}{B(a,b)}
313 * using (a+b) * (p*log(x/p)+q*log(y/q))
314 */
315 Real bt = b1(a, b, x, xm1);
316 if (bt*Arithmetic<Real>::epsilon() == 0.) return lower_tail ? 0. : 1.;
317
318 // initialize numerator
319 Real Nold = 0, Ncur = 1.; // = a_1 = 1
320 // initialize denominator
321 Real Dold = 1., Dcur = xm1 ? 1.-sy/(a+1.) : 1.-sx/(a+1.); // = b_1
322 // normalize if necessary
323 if (std::abs(Dcur) > 4294967296.)
324 {
325 Ncur /= Dcur;
326 Dold /= Dcur;
327 Dcur = 1.;
328 }
329 // auxiliary constant variables
330 const Real x_4 = xm1 ? (0.125 - x/4.) + 0.125 : x/4.;
331 const Real cte_b1 = xm1 ? x/2. + 0.5 : (0.5 - x/2.) + 0.5;
332 const Real cte_b2 = xm1 ? (a-1.)*(b+s-1.)*((0.25-x/2.)+0.25) : (a-1.)*(b+s-1.)*x/2.;
333 const Real cte_a1 = a*(a-2.)*(b+s)*(b+s-2.), cte_a2 = (a-1.)*(b+s-1.)*x_4;
334 // result
335 Real cf = 1/Dcur;
336 // auxiliary variables
337 Real ap2n = a+2., ap2nm1 = a+1.,ap2nm2 = a;
338 // iterations
339 for (int n=1; /*n<=iterMax*/; n++, ap2n += 2., ap2nm1 += 2., ap2nm2 += 2.)
340 {
341 // compute a_n
343 // check trivial case
344 if (a_n*Arithmetic<Real>::epsilon() == 0.) break;
345 // compute b_n
346 Real b_n = cte_b1 - cte_b2/(ap2nm1*(ap2n+1));
347 // compute numerator and denominator
348 Real anew = b_n * Ncur + a_n * Nold;
349 Nold = Ncur;
350 Ncur = anew;
351 // check for underflow
352 if (Ncur*Arithmetic<Real>::epsilon() == 0.) { cf =0.; break;}
353 anew = b_n * Dcur + a_n * Dold;
354 Dold = Dcur;
355 Dcur = anew;
356 // normalize if necessary
357 if (std::abs(Dcur) > 4294967296.)
358 {
359 Ncur /= Dcur;
360 Nold /= Dcur;
361 Dold /= Dcur;
362 Dcur = 1.;
363 }
364 // normalize if necessary with 2^32
365 if (std::abs(Ncur) > 4294967296.)
366 {
367 Ncur /= 4294967296.;
368 Nold /= 4294967296.;
369 Dold /= 4294967296.;
370 Dcur /= 4294967296.;
371 }
372 // test D_n not too small
373 if (std::abs(Dcur) != 0)
374 {
375 Real cfold = cf;
376 cf = Ncur/Dcur;
377 // check cv
378 if (std::abs(cf - cfold) < std::abs(cf)*Arithmetic<Real>::epsilon()) { break;}
379 }
380 }
381 return lower_tail ? bt*cf/a : 1-bt*cf/a;
382}
383
394static Real coefs_odd_se(std::vector<Real> &A)
395{
396 // get the index of the current coefficient (should be n = 2 * l with l>=1)
397 int n = A.size()-1;
398 int l = n/2;
399
400 // initialize the sums
401 Real U2lp1 =A[1]*A[n-1], T2lp1 =0;
402 for (int k=2; k<l; k++)
403 {
404 U2lp1 += A[k] * A[n-k];
405 T2lp1 += A[k+1]*A[n+1-k];
406 }
407 // compute the result
408 Real res = -( A[2]*A[n]*(n-1.)
409 + 2* U2lp1 + (n+2.) * T2lp1
410 + A[l]*A[l] + (l+1.) * A[l+1]*A[l+1]
411 ) / ((n+2.) * A[1]);
412 // save it in A
413 A.push_back(res);
414 // and return it
415 return res;
416}
417
428static Real coefs_even_se( std::vector<Real> &A)
429{
430 // get the current coefficient (should be n = 2 * l - 1 with l>=1)
431 int n = A.size()-1;
432 int l = (n+1)/2;
433 // initialize the sums
434 Real U2l =A[1]*A[n-1], T2l =0;
435 // update sum
436 for (int k=2; k<l; k++)
437 {
438 U2l += A[k]*A[n-k];
439 T2l += A[k+1] *A[n+1-k];
440 }
441 // compute the result
442 Real res = -(A[2]*A[n]*(n-1.) + 2.*U2l + (n+2.) * T2l ) / ((n+2.) * A[1]);
443 // save it in A
444 A.push_back(res);
445 // and return it
446 return res;
447}
448
449/* @ingroup Analysis
450 * @brief compute the coefficients of the beta Ratio function
451 * asymptotic expansion.
452 *
453 * Given the n=2l+1 first coefficients, compute and return the (2l+2)-th
454 * coefficient. The value is stored to the back of the Vector.
455 *
456 * @param A vector of dimension 0:n, n=5,7,... of the coefficients
457 * @return the (n+1)-th coefficient
458 */
459//static Real coefs_se( std::vector<Real> &A)
460//{
461// // get the number of existing coefficient
462// int n = A.size();
463// // sum
464// Real Sn =2*A[1]*A[n-2];
465// for (int k=2; k<=n-3; k++)
466// { Sn += (k+1) * A[k+1]*A[n-k] + A[k] * A[n-1-k];}
467// // compute the result
468// Real res = -((n-2.)*A[2]*A[n-1]/A[1] + Sn/A[1]) / (n+1.);
469// // save it in A
470// A.push_back(res);
471// // and return it
472// return res;
473//}
474
486Real betaRatio_se( Real const& a, Real const& b, Real const& x
487 , bool xm1, bool lower_tail
488 )
489{
490#ifdef STK_BETARATIO_DEBUG
491 stk_cout << _T("BetaRatio_se(") << a << _T(", ") << b << _T(", ") << x << _T(")\n");
492#endif
493 // parameters
494 Real s = a+b, p = a/s, q = b/s, sx = s*x, sy = s-sx;
495 //Real z2 = 2 * (a+b) (p*log(x/p)+q*log(y/q));
496 Real z2 = 2. * (xm1 ? dev0(a, sy)+dev0(b, sx) : dev0(a, sx)+dev0(b, sy));
497 Real z = (((x<p)&&!xm1)||((x>q)&&xm1)) ? -std::sqrt(z2) : std::sqrt(z2);
498 // Compute normal cdf
500 // Compute normal pdf
501 Real dnorm = Const::_1_SQRT2PI_ * exp(-z2/2.);
502 // check large values of z
503 if (dnorm < Arithmetic<Real>::epsilon()) return pnorm;
504
505 // auxiliary variables
506 Real a1 = std::sqrt(a)*std::sqrt(b)/s, a2 = (b - a)/(3.*s), a2_a1 = a2/a1, sqrts = std::sqrt(s);
507
508 // series coefs
509 std::vector<Real> A, B;
510 A.reserve(10); // reserve enough space
511 A.push_back(p); // a0
512 A.push_back(a1); // a1
513 A.push_back(a2); // a2
514 A.push_back(a1 * (a2_a1/2.+0.5) * (a2_a1/2.-0.5)); //a3
515 A.push_back(-0.4*a2*((a2_a1/2.+0.5) * (a2_a1/2.-0.5)+1.)); // a4
516 // compute the numerator and the denominator
517 Real num = (a2 * 2.
518 + (A[3] * 3. * z
519 + (A[4] * 4. * (2+ z2)
520 + (coefs_odd_se(A) * 5. * z * (3 + z2)
521 + (coefs_even_se(A) * 6. * (2*4 + z2 * (4. + z2))
522 + (coefs_odd_se(A) * 7. * z *(5*3 + z2*(5 + z2))
523 + (coefs_even_se(A) * 8. * (2*4*6 + z2 * (4*6 + z2 *(6 + z2)))
524 + (coefs_odd_se(A) * 9. * z * (7*5*3 + z2 * (7*5 + z2 * (7+z2)))
525 + (coefs_even_se(A) * 10. * (2*4*6*8 + z2 * (4*6*8 + z2 *(6*8 + z2 * (8 + z2))))
526 + (coefs_odd_se(A) * 11. * z * (9*7*5*3 + z2 * (9*7*5 + z2 * (9*7+z2 * (9 + z2))))
528 Real den = a1 + (A[3] + (A[5] + (A[7] + (A[9] + A[11] * 11./s) * 9./s)*7./s)*5./s)*3./s;
529
530 // compute ratio
531 Real ratio = num/den;
532 // result
533 return lower_tail ? pnorm - ratio * dnorm : pnorm + ratio * dnorm;
534}
535
536/* @ingroup Analysis
537 * Compute the beta ratio function.
538 * \f[
539 * I_x(a,b) = \frac{\int_0^x u^{a-1} (1-u)^{b-1}}{\int_0^\infty u^{a-1} (1-u)^{b-1}} du
540 * \f]
541 * for \f$ 0\leq x \leq 1\f$.
542 *
543 * @param a, b first and second parameters, must be >0
544 * @param x value to evaluate the function
545 * @param lower_tail @c true if we want the lower tail, @c false otherwise
546 **/
547Real betaRatio( Real const& a, Real const& b, Real const& x, bool lower_tail)
548{
549 // Check if a and x are available
550 if ( isNA(a) || isNA(b) || isNA(x) ) return Arithmetic<Real>::NA();
551 // Negative parameter not allowed
552 if ((a<=0)||(b<=0))
554 return betaRatio_raw(a,b,x,lower_tail);
555}
556Real betaRatio_raw( Real const& a, Real const& b, Real const& x, bool lower_tail)
557{
558 // trivial case
559 if (x<=0) return lower_tail ? 0. : 1.;
560 if (x>=1) return lower_tail ? 1. : 0.;
561 // parameters
562 Real p=a/(a+b);
563 // small a,b max(a,b) <= 15
564 if (std::max(a,b)<=15)
565 {
566 if ((a<=1 && x <=0.5)||(b<=1 && x>=0.5))
567 {
568 return (x <=0.5) ? betaRatio_sr(a, b, x, false, lower_tail)
569 : betaRatio_sr(b, a, x, true, !lower_tail);
570 }
571 // (a<=1) and (x>0.5), use serie_up for b
572 if (a<=1) return betaRatio_up(b, a, x, true, !lower_tail);
573 // (b<=1) and (x<0.5), use serie_up for a
574 if (b<=1) return betaRatio_up(a, b, x, false, lower_tail);
575 // min(a,b)>1, use serie_up for a or b
576 return (x <=0.5) ? betaRatio_up(a, b, x, false, lower_tail)
577 : betaRatio_up(b, a, x, true, !lower_tail);
578 }
579 // min(a,b) < 1 and max(a,b) > 15
580 if (std::min(a,b)<=1)
581 {
582// std::cout << "case 1" << std::endl;
583 // case b<=1 and a>=15
584 if (a>=15) return betaRatio_ae(a, b, x, false, lower_tail);
585 // case a<=1 and b>=15
586 if (b>=15) return betaRatio_ae(b, a, x, true, !lower_tail);
587 }
588
589 // ((1<a<=60)) or ((1<b<=60))
590 if ((std::min(a,b)<=60))
591 {
592// std::cout << "case 3.2" << std::endl;
593 return (a<b) ? betaRatio_up(a, b, x, false, lower_tail)
594 : betaRatio_up(b, a, x, true, !lower_tail);
595 }
596 // general case
597 if ((x<0.97*p)||(x>1.03*p))
598 {
599// std::cout << "case 2.1" << std::endl;
600 return (x < p) ? betaRatio_cf(a, b, x, false, lower_tail)
601 : betaRatio_cf(b, a, x, true, !lower_tail);
602 }
603// std::cout << "case 2.2" << std::endl;
604 return (a<b) ? betaRatio_se(a-1, b-1, x, false, lower_tail)
605 : betaRatio_se(b-1, a-1, x, true, !lower_tail);
606}
607
608} // namespace Funct
609
610} // namespace STK
611
612#undef d1
613#undef d2
614#undef d3
615#undef d4
616#undef d5
617#undef d6
618#undef d7
619#undef d8
620
621#endif /* not IS_RTKPP_LIBRARY */
#define d6(z)
#define d8(z)
#define d5(z)
#define d7(z)
#define d4(z)
#define d2(z)
#define d3(z)
const double b1
const double a2
const double a1
#define STKDOMAIN_ERROR_2ARG(Where, Arg1, Arg2, Error)
Definition STK_Macros.h:147
#define stk_cout
Standard stk output stream.
#define _T(x)
Let x unmodified.
The MultidimRegression class allows to regress a multidimensional output variable among a multivariat...
Real dev0(Real const &a, Real const &b)
compute the partial deviance .
Real betaRatio_se(Real const &a, Real const &b, Real const &x, bool xm1, bool lower_tail)
Compute the incomplete beta function ratio I_x(a,b) using the serie expansion method.
Real betaRatio_ae(Real const &a, Real const &b, Real const &x, bool xm1, bool lower_tail)
Compute the incomplete beta function ratio I_x(a,b) using the asymptotic expansion method.
Real log1p(Real const &x)
compute the function .
Real betaRatio(Real const &a, Real const &b, Real const &x, bool lower_tail=true)
Compute the incomplete beta function ratio Compute the beta ratio function.
Real betaRatio_cf(Real const &a, Real const &b, Real x, bool xm1, bool lower_tail=true)
Compute the incomplete beta function ratio using the continued fraction method.
Real betaRatio_up(Real const &a, Real const &b, Real const &x, bool xm1, bool lower_tail)
Compute the incomplete beta function ratio I_x(a,b) using its recurrence formula and its asymptotic e...
Real betaRatio_sr(Real const &a, Real const &b, Real x, bool xm1, bool lower_tail)
Compute the incomplete beta function ratio I_x(a,b) using its series representation.
Real poisson_pdf_raw(Real const &x, Real const &lambda)
Compute the Poisson density.
Real lgammaStirlingError(Real const &z)
Compute the error when we compute using the Stirling's formula.
Real normal_cdf_raw(Real const &x)
Compute the cumulative distribution function of the normal density.
Real gammaRatioQ(Real const &a, Real const &x)
Compute the incomplete gamma function ratio Q(a,x).
Real gammaRatioP(Real const &a, Real const &x)
Compute the incomplete gamma function ratio P(a,x).
bool isNA(Type const &x)
utility method allowing to know if a value is a NA (Not Available) value
Arrays::SumOp< Lhs, Rhs >::result_type sum(Lhs const &lhs, Rhs const &rhs)
convenience function for summing two arrays
double Real
STK fundamental type of Real values.
Real betaRatio_raw(Real const &a, Real const &b, Real const &x, bool lower_tail)
The namespace STK is the main domain space of the Statistical ToolKit project.
Arithmetic properties of STK fundamental types.
static Type NA()
Adding a Non Available (NA) special number.