2012-11-29 16:39:20 +00:00
|
|
|
# Copyright (c) 2012, GPy authors (see AUTHORS.txt).
|
|
|
|
|
# Licensed under the BSD 3-clause license (see LICENSE.txt)
|
|
|
|
|
|
|
|
|
|
|
2012-11-29 16:25:27 +00:00
|
|
|
import numpy as np
|
|
|
|
|
import pylab as pb
|
|
|
|
|
from scipy.special import gammaln, digamma
|
2013-12-16 13:45:24 +00:00
|
|
|
from ...util.linalg import pdinv
|
|
|
|
|
from domains import _REAL, _POSITIVE
|
2013-06-04 17:03:29 +01:00
|
|
|
import warnings
|
2013-10-17 14:38:43 +01:00
|
|
|
import weakref
|
2012-11-29 16:25:27 +00:00
|
|
|
|
2013-06-04 17:21:56 +01:00
|
|
|
class Prior:
|
2013-06-04 17:03:29 +01:00
|
|
|
domain = None
|
2013-10-17 14:38:43 +01:00
|
|
|
|
2013-06-04 17:03:29 +01:00
|
|
|
def pdf(self, x):
|
2013-01-27 18:12:29 +00:00
|
|
|
return np.exp(self.lnpdf(x))
|
2013-01-27 18:23:19 +00:00
|
|
|
|
2013-01-27 18:12:29 +00:00
|
|
|
def plot(self):
|
|
|
|
|
rvs = self.rvs(1000)
|
2013-06-04 17:03:29 +01:00
|
|
|
pb.hist(rvs, 100, normed=True)
|
|
|
|
|
xmin, xmax = pb.xlim()
|
|
|
|
|
xx = np.linspace(xmin, xmax, 1000)
|
|
|
|
|
pb.plot(xx, self.pdf(xx), 'r', linewidth=2)
|
2012-11-29 16:25:27 +00:00
|
|
|
|
2013-01-27 18:23:19 +00:00
|
|
|
|
2013-06-04 17:21:56 +01:00
|
|
|
class Gaussian(Prior):
|
2013-01-27 18:12:29 +00:00
|
|
|
"""
|
2013-01-27 18:23:19 +00:00
|
|
|
Implementation of the univariate Gaussian probability function, coupled with random variables.
|
|
|
|
|
|
|
|
|
|
:param mu: mean
|
|
|
|
|
:param sigma: standard deviation
|
|
|
|
|
|
|
|
|
|
.. Note:: Bishop 2006 notation is used throughout the code
|
|
|
|
|
|
|
|
|
|
"""
|
2013-10-11 17:26:04 +01:00
|
|
|
domain = _REAL
|
2013-10-17 14:38:43 +01:00
|
|
|
_instances = []
|
|
|
|
|
def __new__(cls, mu, sigma): # Singleton:
|
|
|
|
|
if cls._instances:
|
|
|
|
|
cls._instances[:] = [instance for instance in cls._instances if instance()]
|
|
|
|
|
for instance in cls._instances:
|
|
|
|
|
if instance().mu == mu and instance().sigma == sigma:
|
|
|
|
|
return instance()
|
|
|
|
|
o = super(Prior, cls).__new__(cls, mu, sigma)
|
|
|
|
|
cls._instances.append(weakref.ref(o))
|
|
|
|
|
return cls._instances[-1]()
|
2013-06-04 17:03:29 +01:00
|
|
|
def __init__(self, mu, sigma):
|
2013-01-27 18:12:29 +00:00
|
|
|
self.mu = float(mu)
|
|
|
|
|
self.sigma = float(sigma)
|
|
|
|
|
self.sigma2 = np.square(self.sigma)
|
2013-06-04 17:03:29 +01:00
|
|
|
self.constant = -0.5 * np.log(2 * np.pi * self.sigma2)
|
2013-01-27 18:23:19 +00:00
|
|
|
|
2013-01-27 18:12:29 +00:00
|
|
|
def __str__(self):
|
2013-06-04 17:03:29 +01:00
|
|
|
return "N(" + str(np.round(self.mu)) + ', ' + str(np.round(self.sigma2)) + ')'
|
2013-01-27 18:23:19 +00:00
|
|
|
|
2013-06-04 17:03:29 +01:00
|
|
|
def lnpdf(self, x):
|
|
|
|
|
return self.constant - 0.5 * np.square(x - self.mu) / self.sigma2
|
2013-01-27 18:23:19 +00:00
|
|
|
|
2013-06-04 17:03:29 +01:00
|
|
|
def lnpdf_grad(self, x):
|
|
|
|
|
return -(x - self.mu) / self.sigma2
|
2013-01-27 18:23:19 +00:00
|
|
|
|
2013-06-04 17:03:29 +01:00
|
|
|
def rvs(self, n):
|
|
|
|
|
return np.random.randn(n) * self.sigma + self.mu
|
2012-11-29 16:25:27 +00:00
|
|
|
|
2013-01-27 18:23:19 +00:00
|
|
|
|
2013-06-04 17:21:56 +01:00
|
|
|
class LogGaussian(Prior):
|
2013-01-27 18:12:29 +00:00
|
|
|
"""
|
2013-01-27 18:23:19 +00:00
|
|
|
Implementation of the univariate *log*-Gaussian probability function, coupled with random variables.
|
|
|
|
|
|
|
|
|
|
:param mu: mean
|
|
|
|
|
:param sigma: standard deviation
|
|
|
|
|
|
|
|
|
|
.. Note:: Bishop 2006 notation is used throughout the code
|
|
|
|
|
|
2013-01-27 18:12:29 +00:00
|
|
|
"""
|
2013-10-11 17:26:04 +01:00
|
|
|
domain = _POSITIVE
|
2013-10-17 14:38:43 +01:00
|
|
|
_instances = []
|
|
|
|
|
def __new__(cls, mu, sigma): # Singleton:
|
|
|
|
|
if cls._instances:
|
|
|
|
|
cls._instances[:] = [instance for instance in cls._instances if instance()]
|
|
|
|
|
for instance in cls._instances:
|
|
|
|
|
if instance().mu == mu and instance().sigma == sigma:
|
|
|
|
|
return instance()
|
|
|
|
|
o = super(Prior, cls).__new__(cls, mu, sigma)
|
|
|
|
|
cls._instances.append(weakref.ref(o))
|
|
|
|
|
return cls._instances[-1]()
|
2013-06-04 17:03:29 +01:00
|
|
|
def __init__(self, mu, sigma):
|
2013-01-27 18:12:29 +00:00
|
|
|
self.mu = float(mu)
|
|
|
|
|
self.sigma = float(sigma)
|
|
|
|
|
self.sigma2 = np.square(self.sigma)
|
2013-06-04 17:03:29 +01:00
|
|
|
self.constant = -0.5 * np.log(2 * np.pi * self.sigma2)
|
2013-01-27 18:23:19 +00:00
|
|
|
|
2013-01-27 18:12:29 +00:00
|
|
|
def __str__(self):
|
2013-06-04 17:03:29 +01:00
|
|
|
return "lnN(" + str(np.round(self.mu)) + ', ' + str(np.round(self.sigma2)) + ')'
|
2013-01-27 18:23:19 +00:00
|
|
|
|
2013-06-04 17:03:29 +01:00
|
|
|
def lnpdf(self, x):
|
|
|
|
|
return self.constant - 0.5 * np.square(np.log(x) - self.mu) / self.sigma2 - np.log(x)
|
2013-01-27 18:23:19 +00:00
|
|
|
|
2013-06-04 17:03:29 +01:00
|
|
|
def lnpdf_grad(self, x):
|
|
|
|
|
return -((np.log(x) - self.mu) / self.sigma2 + 1.) / x
|
2013-01-27 18:23:19 +00:00
|
|
|
|
2013-06-04 17:03:29 +01:00
|
|
|
def rvs(self, n):
|
|
|
|
|
return np.exp(np.random.randn(n) * self.sigma + self.mu)
|
2012-11-29 16:25:27 +00:00
|
|
|
|
2013-01-27 18:23:19 +00:00
|
|
|
|
2013-06-04 17:21:56 +01:00
|
|
|
class MultivariateGaussian:
|
2013-01-27 18:12:29 +00:00
|
|
|
"""
|
2013-01-27 18:23:19 +00:00
|
|
|
Implementation of the multivariate Gaussian probability function, coupled with random variables.
|
|
|
|
|
|
|
|
|
|
:param mu: mean (N-dimensional array)
|
|
|
|
|
:param var: covariance matrix (NxN)
|
|
|
|
|
|
|
|
|
|
.. Note:: Bishop 2006 notation is used throughout the code
|
|
|
|
|
|
|
|
|
|
"""
|
2013-10-11 17:26:04 +01:00
|
|
|
domain = _REAL
|
2013-10-17 14:38:43 +01:00
|
|
|
_instances = []
|
|
|
|
|
def __new__(cls, mu, var): # Singleton:
|
|
|
|
|
if cls._instances:
|
|
|
|
|
cls._instances[:] = [instance for instance in cls._instances if instance()]
|
|
|
|
|
for instance in cls._instances:
|
|
|
|
|
if np.all(instance().mu == mu) and np.all(instance().var == var):
|
|
|
|
|
return instance()
|
|
|
|
|
o = super(Prior, cls).__new__(cls, mu, var)
|
|
|
|
|
cls._instances.append(weakref.ref(o))
|
|
|
|
|
return cls._instances[-1]()
|
2013-06-04 17:03:29 +01:00
|
|
|
def __init__(self, mu, var):
|
2013-01-27 18:12:29 +00:00
|
|
|
self.mu = np.array(mu).flatten()
|
|
|
|
|
self.var = np.array(var)
|
2013-06-04 17:03:29 +01:00
|
|
|
assert len(self.var.shape) == 2
|
|
|
|
|
assert self.var.shape[0] == self.var.shape[1]
|
|
|
|
|
assert self.var.shape[0] == self.mu.size
|
2013-06-05 13:02:03 +01:00
|
|
|
self.input_dim = self.mu.size
|
2013-01-27 18:12:29 +00:00
|
|
|
self.inv, self.hld = pdinv(self.var)
|
2013-06-05 13:02:03 +01:00
|
|
|
self.constant = -0.5 * self.input_dim * np.log(2 * np.pi) - self.hld
|
2012-11-29 16:25:27 +00:00
|
|
|
|
2013-01-27 18:12:29 +00:00
|
|
|
def summary(self):
|
2013-01-27 18:23:19 +00:00
|
|
|
raise NotImplementedError
|
|
|
|
|
|
2013-06-04 17:03:29 +01:00
|
|
|
def pdf(self, x):
|
2013-01-27 18:12:29 +00:00
|
|
|
return np.exp(self.lnpdf(x))
|
2013-01-27 18:23:19 +00:00
|
|
|
|
2013-06-04 17:03:29 +01:00
|
|
|
def lnpdf(self, x):
|
|
|
|
|
d = x - self.mu
|
|
|
|
|
return self.constant - 0.5 * np.sum(d * np.dot(d, self.inv), 1)
|
2013-01-27 18:23:19 +00:00
|
|
|
|
2013-06-04 17:03:29 +01:00
|
|
|
def lnpdf_grad(self, x):
|
|
|
|
|
d = x - self.mu
|
|
|
|
|
return -np.dot(self.inv, d)
|
2013-01-27 18:23:19 +00:00
|
|
|
|
2013-06-04 17:03:29 +01:00
|
|
|
def rvs(self, n):
|
|
|
|
|
return np.random.multivariate_normal(self.mu, self.var, n)
|
2013-01-27 18:23:19 +00:00
|
|
|
|
2013-01-27 18:12:29 +00:00
|
|
|
def plot(self):
|
2013-06-05 13:02:03 +01:00
|
|
|
if self.input_dim == 2:
|
2013-01-27 18:12:29 +00:00
|
|
|
rvs = self.rvs(200)
|
2013-06-04 17:03:29 +01:00
|
|
|
pb.plot(rvs[:, 0], rvs[:, 1], 'kx', mew=1.5)
|
|
|
|
|
xmin, xmax = pb.xlim()
|
|
|
|
|
ymin, ymax = pb.ylim()
|
2013-01-27 18:12:29 +00:00
|
|
|
xx, yy = np.mgrid[xmin:xmax:100j, ymin:ymax:100j]
|
2013-06-04 17:03:29 +01:00
|
|
|
xflat = np.vstack((xx.flatten(), yy.flatten())).T
|
|
|
|
|
zz = self.pdf(xflat).reshape(100, 100)
|
|
|
|
|
pb.contour(xx, yy, zz, linewidths=2)
|
2012-11-29 16:25:27 +00:00
|
|
|
|
|
|
|
|
|
2013-06-04 17:03:29 +01:00
|
|
|
def gamma_from_EV(E, V):
|
|
|
|
|
warnings.warn("use Gamma.from_EV to create Gamma Prior", FutureWarning)
|
2013-06-04 17:21:56 +01:00
|
|
|
return Gamma.from_EV(E, V)
|
2012-11-29 16:25:27 +00:00
|
|
|
|
2013-06-04 18:09:02 +01:00
|
|
|
|
2013-06-04 17:21:56 +01:00
|
|
|
class Gamma(Prior):
|
2013-01-27 18:12:29 +00:00
|
|
|
"""
|
2013-01-27 18:23:19 +00:00
|
|
|
Implementation of the Gamma probability function, coupled with random variables.
|
|
|
|
|
|
|
|
|
|
:param a: shape parameter
|
|
|
|
|
:param b: rate parameter (warning: it's the *inverse* of the scale)
|
|
|
|
|
|
|
|
|
|
.. Note:: Bishop 2006 notation is used throughout the code
|
|
|
|
|
|
2013-01-27 18:12:29 +00:00
|
|
|
"""
|
2013-10-11 17:26:04 +01:00
|
|
|
domain = _POSITIVE
|
2013-10-17 14:38:43 +01:00
|
|
|
_instances = []
|
|
|
|
|
def __new__(cls, a, b): # Singleton:
|
|
|
|
|
if cls._instances:
|
|
|
|
|
cls._instances[:] = [instance for instance in cls._instances if instance()]
|
|
|
|
|
for instance in cls._instances:
|
|
|
|
|
if instance().a == a and instance().b == b:
|
|
|
|
|
return instance()
|
|
|
|
|
o = super(Prior, cls).__new__(cls, a, b)
|
|
|
|
|
cls._instances.append(weakref.ref(o))
|
|
|
|
|
return cls._instances[-1]()
|
2013-06-04 17:03:29 +01:00
|
|
|
def __init__(self, a, b):
|
2013-01-27 18:12:29 +00:00
|
|
|
self.a = float(a)
|
|
|
|
|
self.b = float(b)
|
2013-06-04 17:03:29 +01:00
|
|
|
self.constant = -gammaln(self.a) + a * np.log(b)
|
2013-01-27 18:23:19 +00:00
|
|
|
|
2013-01-27 18:12:29 +00:00
|
|
|
def __str__(self):
|
2013-06-04 17:03:29 +01:00
|
|
|
return "Ga(" + str(np.round(self.a)) + ', ' + str(np.round(self.b)) + ')'
|
2013-01-27 18:23:19 +00:00
|
|
|
|
2013-01-27 18:12:29 +00:00
|
|
|
def summary(self):
|
2013-06-04 17:03:29 +01:00
|
|
|
ret = {"E[x]": self.a / self.b, \
|
|
|
|
|
"E[ln x]": digamma(self.a) - np.log(self.b), \
|
|
|
|
|
"var[x]": self.a / self.b / self.b, \
|
|
|
|
|
"Entropy": gammaln(self.a) - (self.a - 1.) * digamma(self.a) - np.log(self.b) + self.a}
|
|
|
|
|
if self.a > 1:
|
|
|
|
|
ret['Mode'] = (self.a - 1.) / self.b
|
2013-01-27 18:12:29 +00:00
|
|
|
else:
|
|
|
|
|
ret['mode'] = np.nan
|
|
|
|
|
return ret
|
2013-01-27 18:23:19 +00:00
|
|
|
|
2013-06-04 17:03:29 +01:00
|
|
|
def lnpdf(self, x):
|
|
|
|
|
return self.constant + (self.a - 1) * np.log(x) - self.b * x
|
2013-01-27 18:23:19 +00:00
|
|
|
|
2013-06-04 17:03:29 +01:00
|
|
|
def lnpdf_grad(self, x):
|
|
|
|
|
return (self.a - 1.) / x - self.b
|
2013-01-27 18:23:19 +00:00
|
|
|
|
2013-06-04 17:03:29 +01:00
|
|
|
def rvs(self, n):
|
|
|
|
|
return np.random.gamma(scale=1. / self.b, shape=self.a, size=n)
|
2013-06-04 17:21:56 +01:00
|
|
|
@staticmethod
|
|
|
|
|
def from_EV(E, V):
|
|
|
|
|
"""
|
|
|
|
|
Creates an instance of a Gamma Prior by specifying the Expected value(s)
|
|
|
|
|
and Variance(s) of the distribution.
|
|
|
|
|
|
|
|
|
|
:param E: expected value
|
|
|
|
|
:param V: variance
|
|
|
|
|
"""
|
|
|
|
|
a = np.square(E) / V
|
|
|
|
|
b = E / V
|
|
|
|
|
return Gamma(a, b)
|
|
|
|
|
|
|
|
|
|
class inverse_gamma(Prior):
|
2013-05-20 11:03:35 +01:00
|
|
|
"""
|
|
|
|
|
Implementation of the inverse-Gamma probability function, coupled with random variables.
|
|
|
|
|
|
|
|
|
|
:param a: shape parameter
|
|
|
|
|
:param b: rate parameter (warning: it's the *inverse* of the scale)
|
|
|
|
|
|
|
|
|
|
.. Note:: Bishop 2006 notation is used throughout the code
|
|
|
|
|
|
|
|
|
|
"""
|
2013-10-11 17:26:04 +01:00
|
|
|
domain = _POSITIVE
|
2013-10-17 14:38:43 +01:00
|
|
|
def __new__(cls, a, b): # Singleton:
|
|
|
|
|
if cls._instances:
|
|
|
|
|
cls._instances[:] = [instance for instance in cls._instances if instance()]
|
|
|
|
|
for instance in cls._instances:
|
|
|
|
|
if instance().a == a and instance().b == b:
|
|
|
|
|
return instance()
|
|
|
|
|
o = super(Prior, cls).__new__(cls, a, b)
|
|
|
|
|
cls._instances.append(weakref.ref(o))
|
|
|
|
|
return cls._instances[-1]()
|
2013-06-04 17:03:29 +01:00
|
|
|
def __init__(self, a, b):
|
2013-05-20 11:03:35 +01:00
|
|
|
self.a = float(a)
|
|
|
|
|
self.b = float(b)
|
2013-06-04 17:03:29 +01:00
|
|
|
self.constant = -gammaln(self.a) + a * np.log(b)
|
2013-05-20 11:03:35 +01:00
|
|
|
|
|
|
|
|
def __str__(self):
|
2013-06-04 17:03:29 +01:00
|
|
|
return "iGa(" + str(np.round(self.a)) + ', ' + str(np.round(self.b)) + ')'
|
2013-05-20 11:03:35 +01:00
|
|
|
|
2013-06-04 17:03:29 +01:00
|
|
|
def lnpdf(self, x):
|
|
|
|
|
return self.constant - (self.a + 1) * np.log(x) - self.b / x
|
2013-05-20 11:03:35 +01:00
|
|
|
|
2013-06-04 17:03:29 +01:00
|
|
|
def lnpdf_grad(self, x):
|
|
|
|
|
return -(self.a + 1.) / x + self.b / x ** 2
|
2013-05-20 11:03:35 +01:00
|
|
|
|
2013-06-04 17:03:29 +01:00
|
|
|
def rvs(self, n):
|
|
|
|
|
return 1. / np.random.gamma(scale=1. / self.b, shape=self.a, size=n)
|