def log_z(self, n=500, integration='simpson'): """ Calculate the log partion function. """ from numpy import pi, linspace, max from csb.numeric import log, exp if integration == 'simpson': from csb.numeric import simpson_2d x = linspace(0., 2 * pi, 2 * n + 1) dx = x[1] - x[0] f = -self.beta * self.energy(x) f_max = max(f) f -= f_max I = simpson_2d(exp(f)) return log(I) + f_max + 2 * log(dx) elif integration == 'trapezoidal': from csb.numeric import trapezoidal_2d x = linspace(0., 2 * pi, n) dx = x[1] - x[0] f = -self.beta * self.energy(x) f_max = max(f) f -= f_max I = trapezoidal_2d(exp(f)) return log(I) + f_max + 2 * log(dx) else: raise NotImplementedError( 'Choose from trapezoidal and simpson-rule Integration')
def testExp(self): from csb.numeric import exp, EXP_MAX, EXP_MIN from numpy import exp as ref_exp x = np.linspace(EXP_MIN, EXP_MAX, 100000) self.assertTrue((exp(x) == ref_exp(x)).all()) self.assertEqual(exp(EXP_MAX + 10.), exp(EXP_MAX)) self.assertEqual(exp(10. * EXP_MIN), exp(EXP_MIN))
def estimate_with_fixed_beta(self, data, beta): mu = median(data) v = mean((data - mu) ** 2) alpha = sqrt(v * exp(gammaln(1. / beta) - gammaln(3. / beta))) return mu, alpha
def log_prob(self, x): mu = self.mu beta = self.beta z = (x - mu) / beta return log(1. / beta) - z - exp(-z)
def testTrapezoidal(self): from csb.numeric import trapezoidal, exp x = np.linspace(-10., 10, 1000) y = exp(-0.5 * x * x) / np.sqrt(2 * np.pi) self.assertAlmostEqual(trapezoidal(x, y), 1.0, 10)
def estimate_with_fixed_beta(self, data, beta): mu = median(data) v = mean((data - mu)**2) alpha = sqrt(v * exp(gammaln(1. / beta) - gammaln(3. / beta))) return mu, alpha
def testTruncatedGamma(self): alpha = 2. beta = 1. x_min = 0.1 x_max = 5. x = truncated_gamma(10000, alpha, beta, x_min, x_max) self.assertTrue((x <= x_max).all()) self.assertTrue((x >= x_min).all()) hy, hx = density(x, 100) hx = 0.5 * (hx[1:] + hx[:-1]) hy = hy.astype('d') with warnings.catch_warnings(record=True) as warning: warnings.simplefilter("always") hy /= (hx[1] - hx[0]) * hy.sum() self.assertLessEqual(len(warning), 1) if len(warning) == 1: warning = warning[0] self.assertEqual(warning.category, RuntimeWarning) self.assertTrue( str(warning.message).startswith( 'divide by zero encountered')) x = numpy.linspace(x_min, x_max, 1000) p = (alpha - 1) * log(x) - beta * x p -= log_sum_exp(p) p = exp(p) / (x[1] - x[0])
def testTruncatedGamma(self): alpha = 2. beta = 1. x_min = 0.1 x_max = 5. x = truncated_gamma(10000, alpha, beta, x_min, x_max) self.assertTrue((x <= x_max).all()) self.assertTrue((x >= x_min).all()) hy, hx = density(x, 100) hx = 0.5 * (hx[1:] + hx[:-1]) hy = hy.astype('d') with warnings.catch_warnings(record=True) as warning: warnings.simplefilter("always") hy /= (hx[1] - hx[0]) * hy.sum() self.assertLessEqual(len(warning), 1) if len(warning) == 1: warning = warning[0] self.assertEqual(warning.category, RuntimeWarning) self.assertTrue(str(warning.message).startswith('divide by zero encountered')) x = numpy.linspace(x_min, x_max, 1000) p = (alpha - 1) * log(x) - beta * x p -= log_sum_exp(p) p = exp(p) / (x[1] - x[0])
def energy(self, raw_energies): from numpy import isinf if isinf(self.beta): m = (raw_energies >= self.e_max).astype('f') return - m * log(0.) else: x = 1 + exp(self.beta * (raw_energies - self.e_max)) return log(x)
def energy(self, raw_energies): from numpy import isinf if isinf(self.beta): m = (raw_energies >= self.e_max).astype('f') return -m * log(0.) else: x = 1 + exp(self.beta * (raw_energies - self.e_max)) return log(x)
def estimate_scales(self, beta=1.0): """ Update scales from current model and samples @param beta: inverse temperature @type beta: float """ from csb.numeric import log, log_sum_exp, exp s_sq = (self.sigma ** 2).clip(1e-300, 1e300) Z = (log(self.w) - 0.5 * (self.delta / s_sq + self.dimension * log(s_sq))) * beta self.scales = exp(Z.T - log_sum_exp(Z.T))
def evaluate(self, x): """ Evaluate the probability of observing values C{x}. @param x: values @type x: array @rtype: array """ x = numpy.array(x) return exp(self.log_prob(x))
def estimate_scales(self, beta=1.0): """ Update scales from current model and samples @param beta: inverse temperature @type beta: float """ from csb.numeric import log, log_sum_exp, exp s_sq = (self.sigma**2).clip(1e-300, 1e300) Z = (log(self.w) - 0.5 * (self.delta / s_sq + self.dimension * log(s_sq))) * beta self.scales = exp(Z.T - log_sum_exp(Z.T))
def entropy(self, n=500): """ Calculate the entropy of the model. @param n: number of integration points for numerical integration @type n: integer """ from csb.numeric import trapezoidal_2d from numpy import pi, linspace, max from csb.numeric import log, exp x = linspace(0., 2 * pi, n) dx = x[1] - x[0] f = -self.beta * self.energy(x) f_max = max(f) log_z = log(trapezoidal_2d(exp(f - f_max))) + f_max + 2 * log(dx) average_energy = trapezoidal_2d(f * exp(f - f_max))\ * exp(f_max + 2 * log(dx) - log_z) return -average_energy + log_z
def sample_beta(kappa, n=1): from numpy import arccos from csb.numeric import log, exp from numpy.random import random u = random(n) if kappa != 0.: x = clip(1 + 2 * log(u + (1 - u) * exp(-kappa)) / kappa, -1., 1.) else: x = 2 * u - 1 if n == 1: return arccos(x)[0] else: return arccos(x)
def inv_digamma_minus_log(y, tol=1e-10, n_iter=100): """ Solve y = psi(alpha) - log(alpha) for alpha by fixed point integration. """ if y >= -log(6.): x = 1 / (2 * (1 - exp(y))) else: x = 1.e-10 for _i in range(n_iter): z = approx_psi(x) - log(x) - y if abs(z) < tol: break x -= x * z / (x * d_approx_psi(x) - 1) x = abs(x) return x
def estimate(self, context, data): """ Generate samples from the posterior of alpha and beta. For beta the posterior is a gamma distribution and analytically acessible. The posterior of alpha can not be expressed analytically and is aproximated using adaptive rejection sampling. """ pdf = GammaPrior() ## sufficient statistics a = numpy.mean(data) b = exp(numpy.mean(log(data))) v = numpy.std(data) ** 2 n = len(data) beta = a / v alpha = beta * a samples = [] for _i in range(self.n_samples): ## sample beta from Gamma distribution beta = numpy.random.gamma(n * alpha + context._hyper_beta.alpha, 1 / (n * a + context._hyper_beta.beta)) ## sample alpha with ARS logp = ARSPosteriorAlpha(n * log(beta * b)\ - context.hyper_alpha.beta, context.hyper_alpha.alpha - 1., n) ars = csb.statistics.ars.ARS(logp) ars.initialize(logp.initial_values()[:2], z0=0.) alpha = ars.sample() if alpha is None: raise ValueError("ARS failed") samples.append((alpha, beta)) pdf.alpha, pdf.beta = samples[-1] return pdf
def testSimpson2D(self): from csb.numeric import simpson_2d, exp from numpy import pi xx = np.linspace(-10., 10, 500) yy = np.linspace(-10., 10, 500) X, Y = np.meshgrid(xx, yy) x = np.array(list(zip(np.ravel(X), np.ravel(Y)))) # mean = np.zeros((2,)) cov = np.eye(2) mu = np.ones(2) # D = 2 q = np.sqrt(np.clip(np.sum((x - mu) * np.dot(x - mu, np.linalg.inv(cov).T), -1), 0., 1e308)) f = exp(-0.5 * q ** 2) / ((2 * pi) * np.sqrt(np.abs(np.linalg.det(cov)))) f = f.reshape((len(xx), len(yy))) I = simpson_2d(f) * (xx[1] - xx[0]) * (yy[1] - yy[0]) self.assertTrue(abs(I - 1.) <= 1e-8)
def testTruncatedNormal(self): mu = 2. sigma = 1. x_min = -1. x_max = 5. x = truncated_normal(10000, mu, sigma, x_min, x_max) self.assertAlmostEqual(numpy.mean(x), mu, delta=1e-1) self.assertAlmostEqual(numpy.var(x), sigma, delta=1e-1) self.assertTrue((x <= x_max).all()) self.assertTrue((x >= x_min).all()) hy, hx = density(x, 100) hx = 0.5 * (hx[1:] + hx[:-1]) hy = hy.astype('d') with warnings.catch_warnings(record=True) as warning: warnings.simplefilter("always") hy /= (hx[1] - hx[0]) * hy.sum() self.assertLessEqual(len(warning), 1) if len(warning) == 1: warning = warning[0] self.assertEqual(warning.category, RuntimeWarning) self.assertTrue( str(warning.message).startswith( 'divide by zero encountered')) x = numpy.linspace(mu - 5 * sigma, mu + 5 * sigma, 1000) p = -0.5 * (x - mu)**2 / sigma**2 p -= log_sum_exp(p) p = exp(p) / (x[1] - x[0])
def testTruncatedNormal(self): mu = 2. sigma = 1. x_min = -1. x_max = 5. x = truncated_normal(10000, mu, sigma, x_min, x_max) self.assertAlmostEqual(numpy.mean(x), mu, delta=1e-1) self.assertAlmostEqual(numpy.var(x), sigma, delta=1e-1) self.assertTrue((x <= x_max).all()) self.assertTrue((x >= x_min).all()) hy, hx = density(x, 100) hx = 0.5 * (hx[1:] + hx[:-1]) hy = hy.astype('d') with warnings.catch_warnings(record=True) as warning: warnings.simplefilter("always") hy /= (hx[1] - hx[0]) * hy.sum() self.assertLessEqual(len(warning), 1) if len(warning) == 1: warning = warning[0] self.assertEqual(warning.category, RuntimeWarning) self.assertTrue(str(warning.message).startswith('divide by zero encountered')) x = numpy.linspace(mu - 5 * sigma, mu + 5 * sigma, 1000) p = -0.5 * (x - mu) ** 2 / sigma ** 2 p -= log_sum_exp(p) p = exp(p) / (x[1] - x[0])
def __call__(self, raw_energies): return exp(-self.energy(raw_energies))
def prob(self, x, y): """ Return the probability of the configurations x cross y. """ from csb.numeric import exp return exp(-self.beta * self(x, y))