def incomplete_beta_ps(a, b, value): """Power series for incomplete beta Use when b*x is small and value not too close to 1. Based on Cephes library by Steve Moshier (incbet.c) """ one = aet.constant(1, dtype="float64") ai = one / a u = (one - b) * value t1 = u / (a + one) t = u threshold = np.MachAr().eps * ai s = aet.constant(0, dtype="float64") def _step(i, t, s): t *= (i - b) * value / i step = t / (a + i) s += step return ((t, s), until(aet.abs_(step) < threshold)) (t, s), _ = scan(_step, sequences=[aet.arange(2, 302)], outputs_info=[e for e in aet.cast((t, s), "float64")]) s = s[-1] + t1 + ai t = gammaln(a + b) - gammaln(a) - gammaln(b) + a * aet.log(value) + aet.log(s) return aet.exp(t)
def logp(self, Z): alpha = self.alpha beta = self.beta Zanchored = Z[self.mask.nonzero()] #import pdb; pdb.set_trace() logp = bound( gammaln(alpha + beta) - gammaln(alpha) - gammaln(beta) + logpow(Zanchored, alpha - 1) + logpow(1 - Zanchored, beta - 1), 0 <= Zanchored, Zanchored <= 1, alpha > 0, beta > 0) return logp
def logp(self, Z): alpha = self.alpha beta = self.beta Zanchored = Z[self.mask.nonzero()] #import pdb; pdb.set_trace() logp = bound( gammaln(alpha + beta) - gammaln(alpha) - gammaln(beta) + logpow( Zanchored, alpha - 1) + logpow(1 - Zanchored, beta - 1), 0 <= Zanchored, Zanchored <= 1, alpha > 0, beta > 0) return logp
def incomplete_beta(a, b, value): """Incomplete beta implementation Power series and continued fraction expansions chosen for best numerical convergence across the board based on inputs. """ machep = aet.constant(np.MachAr().eps, dtype="float64") one = aet.constant(1, dtype="float64") w = one - value ps = incomplete_beta_ps(a, b, value) flip = aet.gt(value, (a / (a + b))) aa, bb = a, b a = aet.switch(flip, bb, aa) b = aet.switch(flip, aa, bb) xc = aet.switch(flip, value, w) x = aet.switch(flip, w, value) tps = incomplete_beta_ps(a, b, x) tps = aet.switch(aet.le(tps, machep), one - machep, one - tps) # Choose which continued fraction expansion for best convergence. small = aet.lt(x * (a + b - 2.0) - (a - one), 0.0) cfe = incomplete_beta_cfe(a, b, x, small) w = aet.switch(small, cfe, cfe / xc) # Direct incomplete beta accounting for flipped a, b. t = aet.exp(a * aet.log(x) + b * aet.log(xc) + gammaln(a + b) - gammaln(a) - gammaln(b) + aet.log(w / a)) t = aet.switch(flip, aet.switch(aet.le(t, machep), one - machep, one - t), t) return aet.switch( aet.and_(flip, aet.and_(aet.le((b * x), one), aet.le(x, 0.95))), tps, aet.switch(aet.and_(aet.le(b * value, one), aet.le(value, 0.95)), ps, t), )
def test_functions(): xvals = list(map(np.atleast_1d, [.01, .1, 2, 100, 10000])) x = tt.dvector('x') x.tag.test_value = xvals[0] p = tt.iscalar('p') p.tag.test_value = 1 gammaln = function([x], ps.gammaln(x)) psi = function([x], ps.psi(x)) function([x, p], ps.multigammaln(x, p)) for x in xvals: yield check_vals, gammaln, ss.gammaln, x for x in xvals[1:]: yield check_vals, psi, ss.psi, x
def test_functions(): xvals = list(map(np.atleast_1d, [0.01, 0.1, 2, 100, 10000])) x = tt.dvector("x") x.tag.test_value = xvals[0] p = tt.iscalar("p") p.tag.test_value = 1 gammaln = function([x], ps.gammaln(x)) psi = function([x], ps.psi(x)) function([x, p], ps.multigammaln(x, p)) for x in xvals: check_vals(gammaln, ss.gammaln, x) for x in xvals[1:]: check_vals(psi, ss.psi, x)
def betaln(x, y): return gammaln(x) + gammaln(y) - gammaln(x + y)
def factln(n): return gammaln(n + 1)