def _betainc(_a, _b, _y): comp = (_a + 1.0) / (_a + _b + 2.0) _cy = 1.0 - _y _poverbeta = pow(_y, _a) * pow(_cy, _b) / beta(_a, _b) if _y < comp: bi = _poverbeta * _betaicf(_a, _b, _y, tolf, itmax) / _a else: bi = 1.0 - _poverbeta * _betaicf(_b, _a, _cy, tolf, itmax) / _b return bi
def cbeta(a, b, x1, x2, x, betaab=False, tolf=FOURMACHEPS, itmax=128): """ The cdf of the beta distribution: f = x**(a-1) * (1-x)**(b-1) / beta(a, b) a, b >= 0; 0 <= x <= 1 F is the integral = the incomplete beta or the incomplete beta ratio function depending on how the incomplete beta function is defined. NB It is possible to gain efficiency by providing the value of the complete beta function beta(a, b) as a pre-computed input (may be computed using numlib.specfunc.beta) instead of the default "False". a and/or b <= 1 is handled using a recurrence formula from Abramowitz & Stegun (G is the gamma function, B is the beta function and I is the incomplete beta): I(a, b, x) = G(a+b) / (G(a+1)*G(b)) * x^a * (1-x)^b + I(a+1, b, x) G(a+b) / (G(a+1)*G(b)) = 1/(a*B(a, b)) I(a, b, x) = 1 - I(b, a, 1-x) I(b, a, 1-x) = G(a+b) / (G(b+1)*G(a)) * x^a * (1-x)^b + I(b+1, a, 1-x) So then - if a < 1: I(a, b, x) = 1/(a*B(a, b)) * x^a * (1-x)^b + I(a+1, b, x) or, if b < 1: I(a, b, x) = 1 - 1/(b*B(a, b)) * x^a * (1-x)^b - I(b+1, a, 1-x) If both a and b < 1 then first I(a+1, b, x) = 1 - 1/(b*B(a+1, b)) * x^(a+1) * (1-x)^b - I(b+1, a+1, 1-x) and then I(a, b, x) = 1/(a*B(a, b)) * x^a * (1-x)^b + I(a+1, b, x) For the general interval must hold that x2 > x1 !!!! """ assert a >= 0.0, "both parameters must be non-negative in cbeta!" assert b >= 0.0, "both parameters must be non-negative in cbeta!" assert x2 >= x1, "support range must not be negative in cbeta!" assert x1 <= x and x <= x2, "variate must be within support range in cbeta!" if a == 1.0 and b == 1.0: return cunifab(x1, x2, x) y = (x - x1) / (x2 - x1) cy = 1.0 - y if y == 0.0: return 0.0 if y == 1.0: return 1.0 # ------------------------------------------------------------------------- def _betainc(_a, _b, _y): comp = (_a + 1.0) / (_a + _b + 2.0) _cy = 1.0 - _y _poverbeta = pow(_y, _a) * pow(_cy, _b) / beta(_a, _b) if _y < comp: bi = _poverbeta * _betaicf(_a, _b, _y, tolf, itmax) / _a else: bi = 1.0 - _poverbeta * _betaicf(_b, _a, _cy, tolf, itmax) / _b return bi # ------------------------------------------------------------------------- if betaab: betaf = betaab else: betaf = beta(a, b) if a <= 1.0 and b <= 1.0: ap1 = a + 1.0 # beta(a, b) = gamma(a) * gamma(b) / gamma(a+b) # beta(a+1, b) = gamma(a+1) * gamma(b) / gamma(a+b+1) # gamma(a+1) = a * gamma(a) # gamma(a+b+1) = (a+b) * gamma(a+b) # beta(a+1, b) = a * gamma(a) * gamma(b) / ((a+b)*gamma(a+b)) = # = a * beta(a, b) / (a+b) betaf1 = a * beta(a, b) / (a + b) # = beta(ap1, b) cdf = 1.0 - (1.0 / (b * betaf1)) * pow(y, ap1) * pow(cy, b) - _betainc(b + 1.0, ap1, cy) poverbeta = pow(y, a) * pow(cy, b) / betaf cdf += poverbeta / a elif a <= 1.0: poverbeta = pow(y, a) * pow(cy, b) / beta(a, b) cdf = poverbeta / a + _betainc(a + 1.0, b, y) elif b <= 1.0: poverbeta = pow(y, a) * pow(cy, b) / beta(a, b) cdf = 1.0 - poverbeta / b - _betainc(b + 1.0, a, cy) else: cdf = _betainc(a, b, y) cdf = kept_within(0.0, cdf, 1.0) return cdf
def cbeta(a, b, x1, x2, x, betaab=False, tolf=FOURMACHEPS, itmax=128): """ The cdf of the beta distribution: f = x**(a-1) * (1-x)**(b-1) / beta(a, b) a, b >= 0; 0 <= x <= 1 F is the integral = the incomplete beta or the incomplete beta ratio function depending on how the incomplete beta function is defined. NB It is possible to gain efficiency by providing the value of the complete beta function beta(a, b) as a pre-computed input (may be computed using numlib.specfunc.beta) instead of the default "False". a and/or b <= 1 is handled using a recurrence formula from Abramowitz & Stegun (G is the gamma function, B is the beta function and I is the incomplete beta): I(a, b, x) = G(a+b) / (G(a+1)*G(b)) * x^a * (1-x)^b + I(a+1, b, x) G(a+b) / (G(a+1)*G(b)) = 1/(a*B(a, b)) I(a, b, x) = 1 - I(b, a, 1-x) I(b, a, 1-x) = G(a+b) / (G(b+1)*G(a)) * x^a * (1-x)^b + I(b+1, a, 1-x) So then - if a < 1: I(a, b, x) = 1/(a*B(a, b)) * x^a * (1-x)^b + I(a+1, b, x) or, if b < 1: I(a, b, x) = 1 - 1/(b*B(a, b)) * x^a * (1-x)^b - I(b+1, a, 1-x) If both a and b < 1 then first I(a+1, b, x) = 1 - 1/(b*B(a+1, b)) * x^(a+1) * (1-x)^b - I(b+1, a+1, 1-x) and then I(a, b, x) = 1/(a*B(a, b)) * x^a * (1-x)^b + I(a+1, b, x) For the general interval must hold that x2 > x1 !!!! """ assert a >= 0.0, "both parameters must be non-negative in cbeta!" assert b >= 0.0, "both parameters must be non-negative in cbeta!" assert x2 >= x1, "support range must not be negative in cbeta!" assert x1 <= x and x <= x2, \ "variate must be within support range in cbeta!" if a == 1.0 and b == 1.0: return cunifab(x1, x2, x) y = (x - x1) / (x2 - x1) cy = 1.0 - y if y == 0.0: return 0.0 if y == 1.0: return 1.0 # ------------------------------------------------------------------------- def _betainc(_a, _b, _y): comp = (_a + 1.0) / (_a + _b + 2.0) _cy = 1.0 - _y _poverbeta = pow(_y, _a) * pow(_cy, _b) / beta(_a, _b) if _y < comp: bi = _poverbeta * _betaicf(_a, _b, _y, tolf, itmax) / _a else: bi = 1.0 - _poverbeta * _betaicf(_b, _a, _cy, tolf, itmax) / _b return bi # ------------------------------------------------------------------------- if betaab: betaf = betaab else: betaf = beta(a, b) if a <= 1.0 and b <= 1.0: ap1 = a + 1.0 # beta(a, b) = gamma(a) * gamma(b) / gamma(a+b) # beta(a+1, b) = gamma(a+1) * gamma(b) / gamma(a+b+1) # gamma(a+1) = a * gamma(a) # gamma(a+b+1) = (a+b) * gamma(a+b) # beta(a+1, b) = a * gamma(a) * gamma(b) / ((a+b)*gamma(a+b)) = # = a * beta(a, b) / (a+b) betaf1 = a * beta(a, b) / (a + b) # = beta(ap1, b) cdf = 1.0 - (1.0/(b*betaf1))*pow(y, ap1)*pow(cy, b) - \ _betainc(b+1.0, ap1, cy) poverbeta = pow(y, a) * pow(cy, b) / betaf cdf += poverbeta / a elif a <= 1.0: poverbeta = pow(y, a) * pow(cy, b) / beta(a, b) cdf = poverbeta / a + _betainc(a + 1.0, b, y) elif b <= 1.0: poverbeta = pow(y, a) * pow(cy, b) / beta(a, b) cdf = 1.0 - poverbeta / b - _betainc(b + 1.0, a, cy) else: cdf = _betainc(a, b, y) cdf = kept_within(0.0, cdf, 1.0) return cdf