Example #1
0
    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)
Example #2
0
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
Example #3
0
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
Example #4
0
    :return: y the result
    """
    # broadcast to circulant
    N, M = x.shape
    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)
Example #5
0
    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
Example #6
0
    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)
Example #7
0
    def __init__(self, t, theta0, solve_mode="full", M=25, L=1.0, jit=1e-4):
        """
        This is a LinearOperator representation of the covariance matrix
        Input:
            t           - inputs
            theta0      - the vector of hyperparameters
            do_inverse  - if True computes the Cholesky factor. If false inverse is computed with preconditioned conjugate gradient.
                          As a rule of thumb this should be False whenever N>1000
            M           - the number of basis functions to use for the preconditioner
            L           - the support of the basis functions
            jit         - jitter for numerical stability of inverse
        """
        # set number of data points
        self.N = t.size

        #self.shape = (self.N, self.N)
        self.Nhypers = theta0.size

        # set inputs
        self.t = t

        from GP.kernels import exponential_squared
        self.kernel = exponential_squared.sqexp()
        #from GP.kernels import mattern
        #self.kernel = mattern.mattern(p=2, D=1)

        # set covariance function and evaluate
        self.theta = theta0
        # set initial jitter factor (for numerical stability of inverse)
        self.jit = jit

        # set derivative
        #self.dcov_func = lambda theta, mode: self.kernel.dcov_func(theta, self.tt, self.val, mode=mode)

        self.solve_mode = solve_mode
        if solve_mode == "full":
            # create vector of differences
            self.tt = np.tile(self.t,
                              (self.N, 1)).T - np.tile(self.t, (self.N, 1))

            # evaluate covaraince matrix
            self.val = self.kernel.cov_func(self.theta, self.tt, noise=False)
            #self.val2 = self.kernel.cov_func2(self.theta, self.tt, noise=False)

            # get cholesky decomp
            self.L = np.linalg.cholesky(
                self.val +
                self.jit * np.eye(self.N))  #add jitter for numerical stability

            # get log determinant (could use entropic trace estimator here)
            self.logdet = 2 * np.sum(np.diag(self.L)).real

            # get the inverse
            self.Linv = np.linalg.inv(self.L)

        # elif solve_mode=="approx" or solve_mode=="RR":
        #     # set up RR basis
        #     from GP.tools import make_basis
        #     from GP.basisfuncs import rectangular
        #     self.M = np.array([M])
        #     self.L = np.array([L])
        #     self.Phi = make_basis.get_eigenvectors(self.t.reshape(self.N, 1), self.M, self.L, rectangular.phi)
        #     Lambda = make_basis.get_eigenvals(self.M, self.L, rectangular.Lambda)
        #     self.s = np.sqrt(Lambda)
        #     # get spectral density
        #     tmp = self.kernel.spectral_density(self.theta, self.s)
        #     self.Lambdainv = diags(1.0/tmp)
        #     self.Sigmainv = diags(np.ones(self.N)/self.jit)
        #
        #     self.Mop = LinearOperator((self.N, self.N), matvec=self.M_func)
        #
        # elif solve_mode=="debug":
        #     # get cholesky decomp
        #     self.L = np.linalg.cholesky(self.val + self.jit * np.eye(self.N))  # add jitter for numerical stability
        #
        #     # get log determinant (could use entropic trace estimator here)
        #     self.logdet = 2 * np.sum(np.diag(self.L)).real
        #
        #     # get the inverse
        #     self.Linv = np.linalg.inv(self.L)
        #
        #     self.valinv = np.dot(self.Linv.T, self.Linv)
        #
        #     # this is for the preconditioning
        #     from GP.tools import make_basis
        #     from GP.basisfuncs import rectangular
        #     self.M = np.array([M])
        #     self.L = np.array([L])
        #     self.Phi = make_basis.get_eigenvectors(self.t.reshape(self.N, 1), self.M, self.L, rectangular.phi)
        #     Lambda = make_basis.get_eigenvals(self.M, self.L, rectangular.Lambda)
        #     self.s = np.sqrt(Lambda)
        #     # get spectral density
        #     tmp = self.kernel.spectral_density(self.theta, self.s) # figure out where factor of 2.5 comes from!!!!!!!!!!!!!!!!!!!!!!!!
        #     self.Lambdainv = np.diag(1.0/tmp)
        #     self.Lambda = np.diag(tmp)
        #     self.Sigmainv = np.diag(np.ones(self.N)/self.jit)
        #
        #     self.val2 = self.Phi.dot(self.Lambda.dot(self.Phi.T))
        #
        #     Z = self.Lambdainv + self.Phi.T.dot(self.Sigmainv.dot(self.Phi))
        #     LZ = np.linalg.cholesky(Z)
        #     LZinv = np.linalg.inv(LZ)
        #     Zinv = np.dot(LZinv.T, LZinv)
        #     self.valinv2 = self.Sigmainv - self.Sigmainv.dot(self.Phi.dot(Zinv.dot(self.Phi.T.dot(self.Sigmainv))))
        #
        #     self.Mop = LinearOperator((self.N, self.N), matvec=self.M_func)
        else:
            raise NotImplementedError("Still working on faster solve_mode")