def __init__(self, x, xp, y, Sigmay=None, covariance_function='sqexp'): """ :param x: an array of arrays holding inputs i.e. x = [[x_1], [x_2], ..., [x_3]] where x_1 in R^{N_1} etc. :param xp: an array of arrays holding targets i.e. xp = [[xp_1], [xp_2], ..., [xp_3]] where xp_1 in R^{Np_1} etc. :param y: an array of arrays holding data i.e. y = [[y_1], [y_2], ..., [y_3]] where y_1 in R^{N_1} etc. :param Sigmay: an array of arrays holding variances i.e. Sigmay = [[Sigmay_1], [Sigmay_2], ..., [Sigmay_3]] where Sigmay_1 in R^{N_1} etc. :param covariance_function: a list holding the covariance functions to use for each dimension """ self.D = x.shape[0] self.N = kt.kron_N(x) self.x = x self.Np = kt.kron_N(xp) self.xp = xp self.y = y if Sigmay is not None: self.Sigmay = Sigmay else: self.Sigmay = None self.covariance_function = covariance_function # initialise the individual diff square grids self.XX = [] self.XXp = [] self.XXpp = [] for i in xrange(self.D): self.XX.append(abs_diff.abs_diff(self.x[i], self.x[i])) self.XXp.append(abs_diff.abs_diff(self.x[i], self.xp[i])) self.XXpp.append(abs_diff.abs_diff(self.xp[i], self.xp[i])) self.XX = np.asarray(self.XX) self.XXp = np.asarray(self.XXp) self.XXpp = np.asarray(self.XXpp) # set the kernels from GP.kernels import exponential_squared # only using this one for now self.kernels = [] self.kernels_transformed = [] for i in xrange(self.D): if self.Sigmay is not None: self.kernels.append(exponential_squared.sqexp(Sigmay=self.Sigmay[i], mode='kron')) #self.kernels_transformed.append(exponential_squared.sqexp(mode='kron')) else: self.kernels.append(exponential_squared.sqexp(mode='kron')) # Instantiate posterior mean, cov and evidence classes self.meano = posterior_mean.meanf(self.x, self.xp, self.y, self.kernels, mode="kron", XX=self.XX, XXp=self.XXp) self.meanf = lambda theta: self.meano.give_mean(theta) self.covo = posterior_covariance.covf(self.kernels, mode="kron", XX=self.XX, XXp=self.XXp, XXpp=self.XXpp) self.covf = lambda theta: self.covo.give_covariance(theta) self.logpo = marginal_posterior.evidence(self.x, self.y, self.kernels, mode="kron", XX=self.XX) self.logp = lambda theta: self.logpo.logL(theta)
def interp(self, tp, theta, gbar): if self.K.solve_mode == "full": # get matrix of differences from GP.tools import abs_diff ttp = abs_diff.abs_diff(self.K.t, tp) ttpp = abs_diff.abs_diff(tp, tp) # get covariance matrices Kp = self.K.kernel.cov_func(theta, ttp, noise=False) Kpp = self.K.kernel.cov_func(theta, ttpp, noise=False) # get the mean function gmean = np.dot(Kp.T, self._idot(gbar)) gcov = Kpp - Kp.T.dot(self._idot(Kp)) return gmean, gcov else: raise NotImplementedError("Still working on faster solve_mode")
def draw_samples_ND_grid(x, theta, Nsamps, meanf=None): """ Draw N dimensional samples on a Euclidean grid :param meanf: mean function :param x: array of arrays containing targets [x_1, x_2, ..., x_D] :param theta: array of arrays containing [theta_1, theta_2, ..., theta_D] :param Nsamps: number of samples to draw :return: array containing samples [Nsamps, N_1, N_2, ..., N_D] """ D = x.shape[0] Ns = [] K = np.empty(D, dtype=object) Kcov = expsq.sqexp() Ntot = 1 for i in xrange(D): Ns.append(x[i].size) XX = abs_diff.abs_diff(x[i], x[i]) print Ns[i], theta[i], K[i] K[i] = Kcov.cov_func(theta[i], XX, noise=False) + 1e-13 * np.eye(Ns[i]) Ntot *= Ns[i] L = kt.kron_cholesky(K) samps = np.zeros([Nsamps] + Ns, dtype=np.float64) for i in xrange(Nsamps): xi = np.random.randn(Ntot) if meanf is not None: samps[i] = meanf(x) + kt.kron_matvec(L, xi).reshape(Ns) else: samps[i] = kt.kron_matvec(L, xi).reshape(Ns) return samps
def draw_spatio_temporal_samples(meanf, x, t, theta_x, theta_t, Nsamps): Nt = t.size Nx = x.size # assumes 1D Ntot = Nt * Nx XX = abs_diff.abs_diff(x, x) TT = abs_diff.abs_diff(t, t) Kcov = expsq.sqexp() Kx = Kcov.cov_func(theta_x, XX, noise=False) + 1e-13 * np.eye(Nx) Kt = Kcov.cov_func(theta_t, TT, noise=False) + 1e-13 * np.eye(Nt) K = np.array([Kt, Kx]) L = kt.kron_cholesky(K) samps = np.zeros([Nsamps, Nt, Nx]) for i in xrange(Nsamps): xi = np.random.randn(Ntot) samps[i] = meanf + kt.kron_matvec(L, xi).reshape(Nt, Nx) return samps
def __init__(self, t, x, tp, xp): """ :param t: T x 1 vector of input times :param x: N x 2 vector of input spatial locations """ self.t = t self.T = t.size # number of time points self.x = x self.N = x.shape[1] # number of spatial points self.M = self.T * self.N # get abs diff of spatial locs and evaluate cov func self.XX = abs_diff.abs_diff(x, x) self.XXp = abs_diff.abs_diff(xp, x) # self.XXpp = self.abs_diff_x(xp, xp) # get abs diff of temporal locs and evaluate cov func self.TT = abs_diff.abs_diff(t, t) self.TTp = abs_diff.abs_diff(tp, t)
def test_tensorvec(x, t, z, N): Nxp = 10 xp = np.linspace(-1, 1, Nxp) xxp = abs_diff.abs_diff(x, xp) Kpx = (kernel.cov_func(thetax, xxp, noise=False)).T Ntp = 12 tp = np.linspace(0, 1, Ntp) ttp = abs_diff.abs_diff(t, tp) Kpt = (kernel.cov_func(thetat, ttp, noise=False)).T Nzp = 14 zp = np.linspace(-0.5, 1, Nzp) zzp = abs_diff.abs_diff(z, zp) Kpz = (kernel.cov_func(thetaz, zzp, noise=False)).T Ap = np.array([Kpz, Kpx, Kpt]) # note ordering!!! Kp = kt.kron_kron(Ap) b = np.random.randn(N) res1 = Kp.dot(b) res2 = kt.kron_tensorvec(Ap, b) compare(res1, res2, 'tensorvec')
c = np.append(t, t[np.arange(N)[1:-1][::-1]].conj()) x_aug = np.append(x, np.zeros([N - 2, M]), axis=0) tmp = FFT_circmat(c, x_aug) return tmp[0:N, :] if __name__ == "__main__": from GP.tools import abs_diff from GP.kernels import exponential_squared # get Toeplitz matrix kernel = exponential_squared.sqexp() Nx = 1024 thetax = np.array([1.0, 0.5]) x = np.linspace(-10, 10, Nx) xx = abs_diff.abs_diff(x, x) Kx = kernel.cov_func(thetax, xx, noise=False) # broadcast to circulant row row1 = np.append(Kx[0, :], Kx[0, np.arange(Nx)[1:-1][::-1]].conj()) # create FFTW objects FFT = pyfftw.builders.rfft iFFT = pyfftw.builders.irfft # test 1D FFT b = np.random.randn(Nx) bhat = FFT(b) b2 = iFFT(bhat())
def draw_samples(meanf, x, theta, cov_func, N): XX = abs_diff.abs_diff(x, x) covf = cov_func(XX, theta) samps = np.random.multivariate_normal(meanf, covf, N) return samps
def reset_targets(self, xp): try: self.Np, D = xp.shape except: self.Np = xp.size D = 1 xp = np.reshape(xp, (self.Np, D)) self.xp = xp if self.mode == "Full": from GP.tools import abs_diff self.XXp = abs_diff.abs_diff(self.x, self.xp) self.XXpp = abs_diff.abs_diff(self.xp, self.xp) # Instantiate posterior mean, cov and evidence classes self.meano = posterior_mean.meanf(self.x, self.xp, self.y, self.kernel, mode=self.mode, prior_mean=self.prior_mean, XX=self.XX, XXp=self.XXp) self.meanf = lambda theta: self.meano.give_mean(theta) self.covo = posterior_covariance.covf(self.kernel, mode=self.mode, XX=self.XX, XXp=self.XXp, XXpp=self.XXpp) self.covf = lambda theta: self.covo.give_covariance(theta) elif self.mode == "RR": from GP.tools import make_basis # Construct the basis functions if self.basis == "Rect": from GP.basisfuncs import rectangular self.Phip = make_basis.get_eigenvectors( self.xp, self.M, self.L, rectangular.phi) else: print "%s basis functions not supported yet" % self.basis self.meano = posterior_mean.meanf(self.x, self.xp, self.y, self.kernel, mode=self.mode, Phi=self.Phi, Phip=self.Phip, PhiTPhi=self.PhiTPhi, s=self.s, prior_mean=self.prior_mean, grid_regular=self.grid_regular) self.meanf = lambda theta: self.meano.give_mean(theta) self.covo = posterior_covariance.covf( self.kernel, mode=self.mode, Phi=self.Phi, Phip=self.Phip, PhiTPhi=self.PhiTPhi, s=self.s, grid_regular=self.grid_regular) self.covf = lambda theta: self.covo.give_covariance(theta) else: raise Exception('Mode %s not supported yet' % self.mode)
def __init__(self, x, xp, y, Sigmay=None, prior_mean=None, covariance_function='sqexp', mode="Full", nu=2.5, basis="Rect", M=12, L=5.0, grid_regular=False): """ :param x: vector of inputs :param xp: vector of targets :param y: vector of data :param prior_mean: a prior mean function (must be callable) :param covariance_function: the kind of covariance function to use (currently 'sqexp' or 'mattern') :param mode: whether to do a full GPR or a reduced rank GPR (currently "Full" or "RR") :param nu: specifies the kind of Mattern function to use (must be a half integer) :param basis: specifies the class of basis functions to use (currently only "Rect") :param M: integer specifying the number of basis functions to use :param L: float specifying the boundary of the domain """ # set inputs and targets enforcing correct sizes self.N = x.shape[0] try: self.D = x.shape[1] self.x = x except: self.D = 1 self.x = x.reshape(self.N, self.D) if self.D > 1: raise Exception("Must pass 1D input to temporal_GP") self.Np = xp.size self.xp = xp.reshape(self.Np, self.D) self.y = y.reshape(self.N, self.D) # check that prior mean is callable and set it try: ym = prior_mean(self.x) self.prior_mean = prior_mean del ym except: raise Exception("Prior mean function must be callable") # set covariance if covariance_function == "sqexp": from GP.kernels import exponential_squared # Initialise kernel self.kernel = exponential_squared.sqexp(Sigmay=Sigmay) elif covariance_function == "mattern": from GP.kernels import mattern # Initialise kernel self.kernel = mattern.mattern(p=int(nu)) else: raise Exception('Kernel %s not supported yet' % covariance_function) # Get inputs required to evaluate covariance function self.mode = mode if mode == "Full": # here we need the differences squared from GP.tools import abs_diff # Initialise absolute differences self.XX = abs_diff.abs_diff(self.x, self.x) self.XXp = abs_diff.abs_diff(self.x, xp) self.XXpp = abs_diff.abs_diff(xp, xp) # Instantiate posterior mean, cov and evidence classes self.meano = posterior_mean.meanf(self.x, self.xp, self.y, self.kernel, mode=self.mode, prior_mean=self.prior_mean, XX=self.XX, XXp=self.XXp) self.meanf = lambda theta: self.meano.give_mean(theta) self.covo = posterior_covariance.covf(self.kernel, mode=self.mode, XX=self.XX, XXp=self.XXp, XXpp=self.XXpp) self.covf = lambda theta: self.covo.give_covariance(theta) self.logpo = marginal_posterior.evidence(self.x, self.y, self.kernel, mode=self.mode, XX=self.XX) self.logp = lambda theta: self.logpo.logL(theta) elif mode == "RR": # here we need to evaluate the basis functions from GP.tools import make_basis # check consistency of inputs if np.asarray(M).size == 1: # 1D so only a single value allowed self.M = np.array([ M ]) # cast as array to make it compatible with make_basis class else: raise Exception( 'Inconsistent dimensions specified for M. Must be 1D.') if np.asarray(L).size == 1: # 1D so only a single value allowed self.L = np.array([ L ]) # cast as array to make it compatible with make_basis class else: raise Exception( 'Inconsistent dimensions specified for L. Must be 1D.') # Construct the basis functions self.basis = basis if self.basis == "Rect": from GP.basisfuncs import rectangular self.Phi = make_basis.get_eigenvectors(self.x, self.M, self.L, rectangular.phi) self.Phip = make_basis.get_eigenvectors( self.xp, self.M, self.L, rectangular.phi) self.Lambda = make_basis.get_eigenvals(self.M, self.L, rectangular.Lambda) else: print "%s basis functions not supported yet" % basis # Precompute some terms that never change # If inputs are on a regular grid we only need the diagonal self.grid_regular = grid_regular if self.grid_regular: self.PhiTPhi = np.einsum( 'ij,ji->i', self.Phi.T, self.Phi) # computes only the diagonal entries else: self.PhiTPhi = np.dot(self.Phi.T, self.Phi) self.s = np.sqrt(self.Lambda) self.meano = posterior_mean.meanf(self.x, self.xp, self.y, self.kernel, mode=self.mode, Phi=self.Phi, Phip=self.Phip, PhiTPhi=self.PhiTPhi, s=self.s, grid_regular=self.grid_regular, prior_mean=self.prior_mean) self.meanf = lambda theta: self.meano.give_mean(theta) self.covo = posterior_covariance.covf( self.kernel, mode=self.mode, Phi=self.Phi, Phip=self.Phip, PhiTPhi=self.PhiTPhi, s=self.s, grid_regular=self.grid_regular) self.covf = lambda theta: self.covo.give_covariance(theta) self.logpo = marginal_posterior.evidence( self.x, self.y, self.kernel, mode=self.mode, Phi=self.Phi, PhiTPhi=self.PhiTPhi, s=self.s, grid_regular=self.grid_regular) self.logp = lambda theta: self.logpo.logL(theta) else: raise Exception('Mode %s not supported yet' % mode) self.has_posterior = False #flag to indicate if the posterior has been computed
import numpy as np from GP.kernels import exponential_squared from GP.tools import make_basis from GP.basisfuncs import rectangular if __name__=="__main__": # set params and get matrix of differences N = 100 Np = 250 tmin = 0.0 tmax = 1.0 t = tmin + (tmax - tmin)*np.sort(np.random.random(N)) tp = np.linspace(tmin, tmax, Np) from GP.tools import abs_diff tt = abs_diff.abs_diff(t, t) # ttp = abs_diff.abs_diff(t, tp) # ttpp = abs_diff.abs_diff(tp, tp) # instantiate kernel kernel = exponential_squared.sqexp() # get some random values of theta to compare RR to full sigfm = 1.0 lm = 0.5 signm = 1.0 thetam = np.array([sigfm, lm, signm]) Ntheta = 10 theta = np.zeros([Ntheta, 3]) deltheta = 1.0e-1
def __init__(self, x, xp, covariance_function='sqexp', mode="Full", nu=2.5, basis="Rect", M=12, L=5.0): """ :param x: vector of inputs :param xp: vector of targets :param covariance_function: the kind of covariance function to use (currently 'sqexp' or 'mattern') :param mode: whether to do a full GPR or a reduced rank GPR (currently "Full" or "RR") :param nu: specifies the kind of Mattern function to use (must be a half integer) :param basis: specifies the class of basis functions to use (currently only "Rect") """ # set inputs and targets try: self.N, self.D = x.shape self.Np = xp.shape[0] except: self.N = x.size self.D = 1 self.Np = xp.size self.x = x self.xp = xp # set covariance if covariance_function == "sqexp": from GP.kernels import exponential_squared # Initialise kernel self.kernel = exponential_squared.sqexp() elif covariance_function == "mattern": from GP.kernels import mattern # Initialise kernel self.kernel = mattern.mattern(p=int(nu)) # Get inputs required to evaluate covariance function self.mode = mode if mode == "Full": # here we need the differences squared from GP.tools import abs_diff # Initialise absolute differences self.XX = abs_diff.abs_diff(x, x) self.XXp = abs_diff.abs_diff(x, xp) self.XXpp = abs_diff.abs_diff(xp, xp) elif mode == "RR": # here we need to evaluate the basis functions from GP.tools import make_basis # check consistency of inputs if np.asarray( M ).size == 1: # if single value is specified for M we use the same number of basis functions for each dimension self.M = np.tile(M, self.D) elif np.asarray(M).size == self.D: self.M = M else: raise Exception('Inconsistent dimensions specified for M') if np.asarray( L ).size == 1: # if single value is specified for L we use square domain (hopefully also circular in future) self.L = np.tile(L, self.D) elif np.asarray(L).size == self.D: self.L = L else: raise Exception('Inconsistent dimensions specified for L') # Construct the basis functions if basis == "Rect": from GP.basisfuncs import rectangular self.Phi = make_basis.get_eigenvectors(self.x, self.M, self.L, rectangular.phi) self.Phip = make_basis.get_eigenvectors( self.xp, self.M, self.L, rectangular.phi) self.Lambda = make_basis.get_eigenvals(self.M, self.L, rectangular.Lambda) else: print "%s basis functions not supported yet" % basis # Precompute some terms that never change self.PhiTPhi = np.dot(self.Phi.T, self.Phi) self.s = np.sqrt(self.Lambda)
def test_Kyopinv(Kyop, K, Sigmay, b): Ky = K + np.diag(Sigmay) res1 = np.linalg.solve(Ky, b) res2 = Kyop.idot(b) compare(res1, res2, "Kyopinv") if __name__ == "__main__": kernel = exponential_squared.sqexp() Nx = 17 sigmaf = 1.0 lx = 0.5 thetax = np.array([sigmaf, lx]) x = np.linspace(-1, 1, Nx) xx = abs_diff.abs_diff(x, x) Kx = kernel.cov_func(thetax, xx, noise=False) Nt = 19 lt = 0.5 thetat = np.array([sigmaf, lt]) t = np.linspace(-1, 1, Nt) tt = abs_diff.abs_diff(t, t) Kt = kernel.cov_func(thetat, tt, noise=False) Nz = 21 lz = 0.5 thetaz = np.array([sigmaf, lz]) z = np.linspace(-1, 1, Nz) zz = abs_diff.abs_diff(z, z) Kz = kernel.cov_func(thetaz, zz, noise=False)