def test_ifelse(self): config1 = aesara.config.profile config2 = aesara.config.profile_memory try: aesara.config.profile = True aesara.config.profile_memory = True a, b = tt.scalars("a", "b") x, y = tt.scalars("x", "y") z = ifelse(tt.lt(a, b), x * 2, y * 2) p = aesara.ProfileStats(False, gpu_checks=False) if aesara.config.mode in ["DebugMode", "DEBUG_MODE", "FAST_COMPILE"]: m = "FAST_RUN" else: m = None f_ifelse = aesara.function( [a, b, x, y], z, profile=p, name="test_ifelse", mode=m ) val1 = 0.0 val2 = 1.0 big_mat1 = 10 big_mat2 = 11 f_ifelse(val1, val2, big_mat1, big_mat2) finally: aesara.config.profile = config1 aesara.config.profile_memory = config2
def logp(value, distribution, lower, upper): """ Calculate log-probability of Bounded distribution at specified value. Parameters ---------- value: numeric Value for which log-probability is calculated. distribution: TensorVariable Distribution which is being bounded lower: numeric Lower bound for the distribution being bounded. upper: numeric Upper bound for the distribution being bounded. Returns ------- TensorVariable """ res = at.switch( at.or_(at.lt(value, lower), at.gt(value, upper)), -np.inf, logp(distribution, value), ) return check_parameters( res, lower <= upper, msg="lower <= upper", )
def _step(i, pkm1, pkm2, qkm1, qkm2, k1, k2, k3, k4, k5, k6, k7, k8, r): xk = -(x * k1 * k2) / (k3 * k4) pk = pkm1 + pkm2 * xk qk = qkm1 + qkm2 * xk pkm2 = pkm1 pkm1 = pk qkm2 = qkm1 qkm1 = qk xk = (x * k5 * k6) / (k7 * k8) pk = pkm1 + pkm2 * xk qk = qkm1 + qkm2 * xk pkm2 = pkm1 pkm1 = pk qkm2 = qkm1 qkm1 = qk old_r = r r = aet.switch(aet.eq(qk, zero), r, pk / qk) k1 += one k2 += k26update k3 += two k4 += two k5 += one k6 -= k26update k7 += two k8 += two big_cond = aet.gt(aet.abs_(qk) + aet.abs_(pk), BIG) biginv_cond = aet.or_(aet.lt(aet.abs_(qk), BIGINV), aet.lt(aet.abs_(pk), BIGINV)) pkm2 = aet.switch(big_cond, pkm2 * BIGINV, pkm2) pkm1 = aet.switch(big_cond, pkm1 * BIGINV, pkm1) qkm2 = aet.switch(big_cond, qkm2 * BIGINV, qkm2) qkm1 = aet.switch(big_cond, qkm1 * BIGINV, qkm1) pkm2 = aet.switch(biginv_cond, pkm2 * BIG, pkm2) pkm1 = aet.switch(biginv_cond, pkm1 * BIG, pkm1) qkm2 = aet.switch(biginv_cond, qkm2 * BIG, qkm2) qkm1 = aet.switch(biginv_cond, qkm1 * BIG, qkm1) return ( (pkm1, pkm2, qkm1, qkm2, k1, k2, k3, k4, k5, k6, k7, k8, r), until(aet.abs_(old_r - r) < (THRESH * aet.abs_(r))), )
def normal_lcdf(mu, sigma, x): """Compute the log of the cumulative density function of the normal.""" z = (x - mu) / sigma return aet.switch( aet.lt(z, -1.0), aet.log(aet.erfcx(-z / aet.sqrt(2.0)) / 2.0) - aet.sqr(z) / 2.0, aet.log1p(-aet.erfc(z / aet.sqrt(2.0)) / 2.0), )
def log_i0(x): """ Calculates the logarithm of the 0 order modified Bessel function of the first kind"" """ return at.switch( at.lt(x, 5), at.log1p(x**2.0 / 4.0 + x**4.0 / 64.0 + x**6.0 / 2304.0 + x**8.0 / 147456.0 + x**10.0 / 14745600.0 + x**12.0 / 2123366400.0), x - 0.5 * at.log(2.0 * np.pi * x) + at.log1p(1.0 / (8.0 * x) + 9.0 / (128.0 * x**2.0) + 225.0 / (3072.0 * x**3.0) + 11025.0 / (98304.0 * x**4.0)), )
def grad(self, inputs, cost_grad): """ In defining the gradient, the Finite Fourier Transform is viewed as a complex-differentiable function of a complex variable """ a = inputs[0] n = inputs[1] axis = inputs[2] grad = cost_grad[0] if not isinstance(axis, tensor.TensorConstant): raise NotImplementedError( "%s: gradient is currently implemented" " only for axis being a Aesara constant" % self.__class__.__name__) axis = int(axis.data) # notice that the number of actual elements in wrto is independent of # possible padding or truncation: elem = tensor.arange(0, tensor.shape(a)[axis], 1) # accounts for padding: freq = tensor.arange(0, n, 1) outer = tensor.outer(freq, elem) pow_outer = tensor.exp(((-2 * math.pi * 1j) * outer) / (1.0 * n)) res = tensor.tensordot(grad, pow_outer, (axis, 0)) # This would be simpler but not implemented by aesara: # res = tensor.switch(tensor.lt(n, tensor.shape(a)[axis]), # tensor.set_subtensor(res[...,n::], 0, False, False), res) # Instead we resort to that to account for truncation: flip_shape = list(np.arange(0, a.ndim)[::-1]) res = res.dimshuffle(flip_shape) res = tensor.switch( tensor.lt(n, tensor.shape(a)[axis]), tensor.set_subtensor( res[n::, ], 0, False, False, ), res, ) res = res.dimshuffle(flip_shape) # insures that gradient shape conforms to input shape: out_shape = (list(np.arange(0, axis)) + [a.ndim - 1] + list(np.arange(axis, a.ndim - 1))) res = res.dimshuffle(*out_shape) return [res, None, None]
def log1mexp(x): r"""Return log(1 - exp(-x)). This function is numerically more stable than the naive approach. For details, see https://cran.r-project.org/web/packages/Rmpfr/vignettes/log1mexp-note.pdf References ---------- .. [Machler2012] Martin Mächler (2012). "Accurately computing `\log(1-\exp(- \mid a \mid))` Assessed by the Rmpfr package" """ return at.switch(at.lt(x, 0.6931471805599453), at.log(-at.expm1(-x)), at.log1p(-at.exp(-x)))
def log_diff_normal_cdf(mu, sigma, x, y): """ Compute :math:`\\log(\\Phi(\frac{x - \\mu}{\\sigma}) - \\Phi(\frac{y - \\mu}{\\sigma}))` safely in log space. Parameters ---------- mu: float mean sigma: float std x: float y: float must be strictly less than x. Returns ------- log (\\Phi(x) - \\Phi(y)) """ x = (x - mu) / sigma / aet.sqrt(2.0) y = (y - mu) / sigma / aet.sqrt(2.0) # To stabilize the computation, consider these three regions: # 1) x > y > 0 => Use erf(x) = 1 - e^{-x^2} erfcx(x) and erf(y) =1 - e^{-y^2} erfcx(y) # 2) 0 > x > y => Use erf(x) = e^{-x^2} erfcx(-x) and erf(y) = e^{-y^2} erfcx(-y) # 3) x > 0 > y => Naive formula log( (erf(x) - erf(y)) / 2 ) works fine. return aet.log(0.5) + aet.switch( aet.gt(y, 0), -aet.square(y) + aet.log( aet.erfcx(y) - aet.exp(aet.square(y) - aet.square(x)) * aet.erfcx(x)), aet.switch( aet.lt(x, 0), # 0 > x > y -aet.square(x) + aet.log( aet.erfcx(-x) - aet.exp(aet.square(x) - aet.square(y)) * aet.erfcx(-y)), aet.log(aet.erf(x) - aet.erf(y)), # x >0 > y ), )
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), )
import time import numpy as np import aesara from aesara import tensor as tt from aesara.ifelse import ifelse a, b = tt.scalars("a", "b") x, y = tt.matrices("x", "y") z_switch = tt.switch(tt.lt(a, b), tt.mean(x), tt.mean(y)) z_lazy = ifelse(tt.lt(a, b), tt.mean(x), tt.mean(y)) f_switch = aesara.function([a, b, x, y], z_switch) f_lazyifelse = aesara.function([a, b, x, y], z_lazy) val1 = 0.0 val2 = 1.0 big_mat1 = np.ones((10000, 1000)) big_mat2 = np.ones((10000, 1000)) n_times = 10 tic = time.clock() for i in range(n_times): f_switch(val1, val2, big_mat1, big_mat2) print("time spent evaluating both values %f sec" % (time.clock() - tic)) tic = time.clock()
def no_shared_fn(n, x_tm1, M): p = M[n, x_tm1] return at.switch(at.lt(zero, p[0]), one, zero)