diff --git a/GPy/core/model.py b/GPy/core/model.py index c067d51d..21bcf0c7 100644 --- a/GPy/core/model.py +++ b/GPy/core/model.py @@ -485,20 +485,17 @@ class Model(Parameterized): if not hasattr(self, 'kern'): raise ValueError, "this model has no kernel" - k = [p for p in self.kern._parameters_ if hasattr(p, "ARD") and p.ARD] - if (not len(k) == 1): - raise ValueError, "cannot determine sensitivity for this kernel" - k = k[0] - from ..kern.parts.rbf import RBF - from ..kern.parts.rbf_inv import RBFInv - from ..kern.parts.linear import Linear + k = self.kern#[p for p in self.kern._parameters_ if hasattr(p, "ARD") and p.ARD] + from ..kern import RBF, Linear#, RBFInv + if isinstance(k, RBF): return 1. / k.lengthscale - elif isinstance(k, RBFInv): - return k.inv_lengthscale + #elif isinstance(k, RBFInv): + # return k.inv_lengthscale elif isinstance(k, Linear): return k.variances - + else: + raise ValueError, "cannot determine sensitivity for this kernel" def pseudo_EM(self, stop_crit=.1, **kwargs): """ diff --git a/GPy/core/parameterization/index_operations.py b/GPy/core/parameterization/index_operations.py index bfd0bf21..b5399741 100644 --- a/GPy/core/parameterization/index_operations.py +++ b/GPy/core/parameterization/index_operations.py @@ -83,11 +83,21 @@ class ParameterIndexOperations(object): def iterproperties(self): return self._properties.iterkeys() - def shift(self, start, size): + def shift_right(self, start, size): for ind in self.iterindices(): toshift = ind>=start - if toshift.size > 0: - ind[toshift] += size + ind[toshift] += size + + def shift_left(self, start, size): + for v, ind in self.items(): + todelete = (ind>=start) * (ind=start + if toshift.size != 0: + ind[toshift] -= size + if ind.size != 0: self._properties[v] = ind + else: del self._properties[v] def clear(self): self._properties.clear() @@ -183,7 +193,7 @@ class ParameterIndexOperationsView(object): yield i - def shift(self, start, size): + def shift_right(self, start, size): raise NotImplementedError, 'Shifting only supported in original ParamIndexOperations' diff --git a/GPy/core/parameterization/parameter_core.py b/GPy/core/parameterization/parameter_core.py index 45b57eab..c2c8a05a 100644 --- a/GPy/core/parameterization/parameter_core.py +++ b/GPy/core/parameterization/parameter_core.py @@ -390,6 +390,7 @@ class Parameterizable(Constrainable): import copy from .index_operations import ParameterIndexOperations, ParameterIndexOperationsView from .array_core import ParamList + dc = dict() for k, v in self.__dict__.iteritems(): if k not in ['_direct_parent_', '_parameters_', '_parent_index_'] + self.parameter_names(): @@ -399,18 +400,21 @@ class Parameterizable(Constrainable): dc[k] = copy.deepcopy(v) if k == '_parameters_': params = [p.copy() for p in v] - # dc = copy.deepcopy(self.__dict__) + dc['_direct_parent_'] = None dc['_parent_index_'] = None dc['_parameters_'] = ParamList() + dc['constraints'].clear() + dc['priors'].clear() + dc['size'] = 0 + s = self.__new__(self.__class__) s.__dict__ = dc - # import ipdb;ipdb.set_trace() + for p in params: s.add_parameter(p) - # dc._notify_parent_change() + return s - # return copy.deepcopy(self) def _notify_parameters_changed(self): self.parameters_changed() diff --git a/GPy/core/parameterization/parameterized.py b/GPy/core/parameterization/parameterized.py index 177cc217..d463ed43 100644 --- a/GPy/core/parameterization/parameterized.py +++ b/GPy/core/parameterization/parameterized.py @@ -87,8 +87,8 @@ class Parameterized(Parameterizable, Pickleable, Observable, Gradcheckable): self._parameters_.append(param) else: start = sum(p.size for p in self._parameters_[:index]) - self.constraints.shift(start, param.size) - self.priors.shift(start, param.size) + self.constraints.shift_right(start, param.size) + self.priors.shift_right(start, param.size) self.constraints.update(param.constraints, start) self.priors.update(param.priors, start) self._parameters_.insert(index, param) @@ -113,15 +113,19 @@ class Parameterized(Parameterizable, Pickleable, Observable, Gradcheckable): """ if not param in self._parameters_: raise RuntimeError, "Parameter {} does not belong to this object, remove parameters directly from their respective parents".format(param._short()) - del self._parameters_[param._parent_index_] + + start = sum([p.size for p in self._parameters_[:param._parent_index_]]) + self._remove_parameter_name(param) self.size -= param.size + del self._parameters_[param._parent_index_] param._disconnect_parent() - self._remove_parameter_name(param) - - #self._notify_parent_change() + self.constraints.shift_left(start, param.size) self._connect_fixes() - + self._connect_parameters() + self._notify_parent_change() + + def _connect_parameters(self): # connect parameterlist to this parameterized object # This just sets up the right connection for the params objects diff --git a/GPy/examples/dimensionality_reduction.py b/GPy/examples/dimensionality_reduction.py index c8e79e6c..3ba54d34 100644 --- a/GPy/examples/dimensionality_reduction.py +++ b/GPy/examples/dimensionality_reduction.py @@ -74,7 +74,7 @@ def gplvm_oil_100(optimize=True, verbose=1, plot=True): data = GPy.util.datasets.oil_100() Y = data['X'] # create simple GP model - kernel = GPy.kern.RBF(6, ARD=True) + GPy.kern.bias(6) + kernel = GPy.kern.RBF(6, ARD=True) + GPy.kern.Bias(6) m = GPy.models.GPLVM(Y, 6, kernel=kernel) m.data_labels = data['Y'].argmax(axis=1) if optimize: m.optimize('scg', messages=verbose) @@ -190,17 +190,22 @@ def _simulate_sincos(D1, D2, D3, N, num_inducing, Q, plot_sim=False): _np.random.seed(1234) x = _np.linspace(0, 4 * _np.pi, N)[:, None] - s1 = _np.vectorize(lambda x: _np.sin(x)) + s1 = _np.vectorize(lambda x: -_np.sin(x)) s2 = _np.vectorize(lambda x: _np.cos(x)) s3 = _np.vectorize(lambda x:-_np.exp(-_np.cos(2 * x))) - sS = _np.vectorize(lambda x: _np.sin(2 * x)) + sS = _np.vectorize(lambda x: x*_np.sin(x)) s1 = s1(x) s2 = s2(x) s3 = s3(x) sS = sS(x) - S1 = _np.hstack([s1, sS]) + s1 -= s1.mean(); s1 /= s1.std(0) + s2 -= s2.mean(); s2 /= s2.std(0) + s3 -= s3.mean(); s3 /= s3.std(0) + sS -= sS.mean(); sS /= sS.std(0) + + S1 = _np.hstack([s1, s2, sS]) S2 = _np.hstack([s2, s3, sS]) S3 = _np.hstack([s3, sS]) @@ -271,7 +276,7 @@ def bgplvm_simulation(optimize=True, verbose=1, D1, D2, D3, N, num_inducing, Q = 15, 5, 8, 30, 3, 10 _, _, Ylist = _simulate_sincos(D1, D2, D3, N, num_inducing, Q, plot_sim) Y = Ylist[0] - k = kern.linear(Q, ARD=True)# + kern.white(Q, _np.exp(-2)) # + kern.bias(Q) + k = kern.Linear(Q, ARD=True)# + kern.white(Q, _np.exp(-2)) # + kern.bias(Q) m = BayesianGPLVM(Y, Q, init="PCA", num_inducing=num_inducing, kernel=k) if optimize: @@ -291,10 +296,10 @@ def bgplvm_simulation_missing_data(optimize=True, verbose=1, from GPy.models import BayesianGPLVM from GPy.inference.latent_function_inference.var_dtc import VarDTCMissingData - D1, D2, D3, N, num_inducing, Q = 15, 5, 8, 30, 3, 10 + D1, D2, D3, N, num_inducing, Q = 15, 5, 8, 30, 5, 9 _, _, Ylist = _simulate_sincos(D1, D2, D3, N, num_inducing, Q, plot_sim) Y = Ylist[0] - k = kern.linear(Q, ARD=True)# + kern.white(Q, _np.exp(-2)) # + kern.bias(Q) + k = kern.Linear(Q, ARD=True)# + kern.white(Q, _np.exp(-2)) # + kern.bias(Q) inan = _np.random.binomial(1, .6, size=Y.shape).astype(bool) m = BayesianGPLVM(Y.copy(), Q, init="random", num_inducing=num_inducing, kernel=k) diff --git a/GPy/inference/latent_function_inference/var_dtc.py b/GPy/inference/latent_function_inference/var_dtc.py index c2f179ac..349cd72d 100644 --- a/GPy/inference/latent_function_inference/var_dtc.py +++ b/GPy/inference/latent_function_inference/var_dtc.py @@ -326,14 +326,14 @@ class VarDTCMissingData(object): # gradients: if uncertain_inputs: grad_dict = {'dL_dKmm': dL_dKmm, - 'dL_dpsi0':dL_dpsi0, - 'dL_dpsi1':dL_dpsi1, - 'dL_dpsi2':dL_dpsi2, + 'dL_dpsi0':dL_dpsi0_all, + 'dL_dpsi1':dL_dpsi1_all, + 'dL_dpsi2':dL_dpsi2_all, 'partial_for_likelihood':partial_for_likelihood} else: grad_dict = {'dL_dKmm': dL_dKmm, - 'dL_dKdiag':dL_dpsi0, - 'dL_dKnm':dL_dpsi1, + 'dL_dKdiag':dL_dpsi0_all, + 'dL_dKnm':dL_dpsi1_all, 'partial_for_likelihood':partial_for_likelihood} #get sufficient things for posterior prediction diff --git a/GPy/kern/__init__.py b/GPy/kern/__init__.py index 16c13066..e5dc6d35 100644 --- a/GPy/kern/__init__.py +++ b/GPy/kern/__init__.py @@ -3,6 +3,7 @@ from _src.white import White from _src.kern import Kern from _src.linear import Linear from _src.brownian import Brownian +from _src.stationary import Exponential, Matern32, Matern52, ExpQuad #from _src.bias import Bias #import coregionalize #import exponential diff --git a/GPy/kern/_src/Matern32.py b/GPy/kern/_src/Matern32.py deleted file mode 100644 index 08fa452c..00000000 --- a/GPy/kern/_src/Matern32.py +++ /dev/null @@ -1,139 +0,0 @@ -# Copyright (c) 2012, GPy authors (see AUTHORS.txt). -# Licensed under the BSD 3-clause license (see LICENSE.txt) - - -from kernpart import Kernpart -import numpy as np -from scipy import integrate - -class Matern32(Kernpart): - """ - Matern 3/2 kernel: - - .. math:: - - k(r) = \\sigma^2 (1 + \\sqrt{3} r) \exp(- \sqrt{3} r) \\ \\ \\ \\ \\text{ where } r = \sqrt{\sum_{i=1}^input_dim \\frac{(x_i-y_i)^2}{\ell_i^2} } - - :param input_dim: the number of input dimensions - :type input_dim: int - :param variance: the variance :math:`\sigma^2` - :type variance: float - :param lengthscale: the vector of lengthscale :math:`\ell_i` - :type lengthscale: array or list of the appropriate size (or float if there is only one lengthscale parameter) - :param ARD: Auto Relevance Determination. If equal to "False", the kernel is isotropic (ie. one single lengthscale parameter \ell), otherwise there is one lengthscale parameter per dimension. - :type ARD: Boolean - :rtype: kernel object - - """ - - def __init__(self, input_dim, variance=1., lengthscale=None, ARD=False): - self.input_dim = input_dim - self.ARD = ARD - if ARD == False: - self.num_params = 2 - self.name = 'Mat32' - if lengthscale is not None: - lengthscale = np.asarray(lengthscale) - assert lengthscale.size == 1, "Only one lengthscale needed for non-ARD kernel" - else: - lengthscale = np.ones(1) - else: - self.num_params = self.input_dim + 1 - self.name = 'Mat32' - if lengthscale is not None: - lengthscale = np.asarray(lengthscale) - assert lengthscale.size == self.input_dim, "bad number of lengthscales" - else: - lengthscale = np.ones(self.input_dim) - self._set_params(np.hstack((variance, lengthscale.flatten()))) - - def _get_params(self): - """return the value of the parameters.""" - return np.hstack((self.variance, self.lengthscale)) - - def _set_params(self, x): - """set the value of the parameters.""" - assert x.size == self.num_params - self.variance = x[0] - self.lengthscale = x[1:] - - def _get_param_names(self): - """return parameter names.""" - if self.num_params == 2: - return ['variance', 'lengthscale'] - else: - return ['variance'] + ['lengthscale_%i' % i for i in range(self.lengthscale.size)] - - def K(self, X, X2, target): - """Compute the covariance matrix between X and X2.""" - if X2 is None: X2 = X - dist = np.sqrt(np.sum(np.square((X[:, None, :] - X2[None, :, :]) / self.lengthscale), -1)) - np.add(self.variance * (1 + np.sqrt(3.) * dist) * np.exp(-np.sqrt(3.) * dist), target, target) - - def Kdiag(self, X, target): - """Compute the diagonal of the covariance matrix associated to X.""" - np.add(target, self.variance, target) - - def _param_grad_helper(self, dL_dK, X, X2, target): - """derivative of the covariance matrix with respect to the parameters.""" - if X2 is None: X2 = X - dist = np.sqrt(np.sum(np.square((X[:, None, :] - X2[None, :, :]) / self.lengthscale), -1)) - dvar = (1 + np.sqrt(3.) * dist) * np.exp(-np.sqrt(3.) * dist) - invdist = 1. / np.where(dist != 0., dist, np.inf) - dist2M = np.square(X[:, None, :] - X2[None, :, :]) / self.lengthscale ** 3 - # dl = (self.variance* 3 * dist * np.exp(-np.sqrt(3.)*dist))[:,:,np.newaxis] * dist2M*invdist[:,:,np.newaxis] - target[0] += np.sum(dvar * dL_dK) - if self.ARD == True: - dl = (self.variance * 3 * dist * np.exp(-np.sqrt(3.) * dist))[:, :, np.newaxis] * dist2M * invdist[:, :, np.newaxis] - # dl = self.variance*dvar[:,:,None]*dist2M*invdist[:,:,None] - target[1:] += (dl * dL_dK[:, :, None]).sum(0).sum(0) - else: - dl = (self.variance * 3 * dist * np.exp(-np.sqrt(3.) * dist)) * dist2M.sum(-1) * invdist - # dl = self.variance*dvar*dist2M.sum(-1)*invdist - target[1] += np.sum(dl * dL_dK) - - def dKdiag_dtheta(self, dL_dKdiag, X, target): - """derivative of the diagonal of the covariance matrix with respect to the parameters.""" - target[0] += np.sum(dL_dKdiag) - - def gradients_X(self, dL_dK, X, X2, target): - """derivative of the covariance matrix with respect to X.""" - if X2 is None: - dist = np.sqrt(np.sum(np.square((X[:, None, :] - X[None, :, :]) / self.lengthscale), -1))[:, :, None] - ddist_dX = 2*(X[:, None, :] - X[None, :, :]) / self.lengthscale ** 2 / np.where(dist != 0., dist, np.inf) - - else: - dist = np.sqrt(np.sum(np.square((X[:, None, :] - X2[None, :, :]) / self.lengthscale), -1))[:, :, None] - ddist_dX = (X[:, None, :] - X2[None, :, :]) / self.lengthscale ** 2 / np.where(dist != 0., dist, np.inf) - gradients_X = -np.transpose(3 * self.variance * dist * np.exp(-np.sqrt(3) * dist) * ddist_dX, (1, 0, 2)) - target += np.sum(gradients_X * dL_dK.T[:, :, None], 0) - - def dKdiag_dX(self, dL_dKdiag, X, target): - pass - - def Gram_matrix(self, F, F1, F2, lower, upper): - """ - Return the Gram matrix of the vector of functions F with respect to the RKHS norm. The use of this function is limited to input_dim=1. - - :param F: vector of functions - :type F: np.array - :param F1: vector of derivatives of F - :type F1: np.array - :param F2: vector of second derivatives of F - :type F2: np.array - :param lower,upper: boundaries of the input domain - :type lower,upper: floats - """ - assert self.input_dim == 1 - def L(x, i): - return(3. / self.lengthscale ** 2 * F[i](x) + 2 * np.sqrt(3) / self.lengthscale * F1[i](x) + F2[i](x)) - n = F.shape[0] - G = np.zeros((n, n)) - for i in range(n): - for j in range(i, n): - G[i, j] = G[j, i] = integrate.quad(lambda x : L(x, i) * L(x, j), lower, upper)[0] - Flower = np.array([f(lower) for f in F])[:, None] - F1lower = np.array([f(lower) for f in F1])[:, None] - # print "OLD \n", np.dot(F1lower,F1lower.T), "\n \n" - # return(G) - return(self.lengthscale ** 3 / (12.*np.sqrt(3) * self.variance) * G + 1. / self.variance * np.dot(Flower, Flower.T) + self.lengthscale ** 2 / (3.*self.variance) * np.dot(F1lower, F1lower.T)) diff --git a/GPy/kern/_src/Matern52.py b/GPy/kern/_src/Matern52.py deleted file mode 100644 index 7d36254c..00000000 --- a/GPy/kern/_src/Matern52.py +++ /dev/null @@ -1,145 +0,0 @@ -# Copyright (c) 2012, GPy authors (see AUTHORS.txt). -# Licensed under the BSD 3-clause license (see LICENSE.txt) - - -from kernpart import Kernpart -import numpy as np -import hashlib -from scipy import integrate - -class Matern52(Kernpart): - """ - Matern 5/2 kernel: - - .. math:: - - k(r) = \sigma^2 (1 + \sqrt{5} r + \\frac53 r^2) \exp(- \sqrt{5} r) \ \ \ \ \ \\text{ where } r = \sqrt{\sum_{i=1}^input_dim \\frac{(x_i-y_i)^2}{\ell_i^2} } - - :param input_dim: the number of input dimensions - :type input_dim: int - :param variance: the variance :math:`\sigma^2` - :type variance: float - :param lengthscale: the vector of lengthscale :math:`\ell_i` - :type lengthscale: array or list of the appropriate size (or float if there is only one lengthscale parameter) - :param ARD: Auto Relevance Determination. If equal to "False", the kernel is isotropic (ie. one single lengthscale parameter \ell), otherwise there is one lengthscale parameter per dimension. - :type ARD: Boolean - :rtype: kernel object - - """ - def __init__(self,input_dim,variance=1.,lengthscale=None,ARD=False): - self.input_dim = input_dim - self.ARD = ARD - if ARD == False: - self.num_params = 2 - self.name = 'Mat52' - if lengthscale is not None: - lengthscale = np.asarray(lengthscale) - assert lengthscale.size == 1, "Only one lengthscale needed for non-ARD kernel" - else: - lengthscale = np.ones(1) - else: - self.num_params = self.input_dim + 1 - self.name = 'Mat52' - if lengthscale is not None: - lengthscale = np.asarray(lengthscale) - assert lengthscale.size == self.input_dim, "bad number of lengthscales" - else: - lengthscale = np.ones(self.input_dim) - self._set_params(np.hstack((variance,lengthscale.flatten()))) - - def _get_params(self): - """return the value of the parameters.""" - return np.hstack((self.variance,self.lengthscale)) - - def _set_params(self,x): - """set the value of the parameters.""" - assert x.size == self.num_params - self.variance = x[0] - self.lengthscale = x[1:] - - def _get_param_names(self): - """return parameter names.""" - if self.num_params == 2: - return ['variance','lengthscale'] - else: - return ['variance']+['lengthscale_%i'%i for i in range(self.lengthscale.size)] - - def K(self,X,X2,target): - """Compute the covariance matrix between X and X2.""" - if X2 is None: X2 = X - dist = np.sqrt(np.sum(np.square((X[:,None,:]-X2[None,:,:])/self.lengthscale),-1)) - np.add(self.variance*(1+np.sqrt(5.)*dist+5./3*dist**2)*np.exp(-np.sqrt(5.)*dist), target,target) - - def Kdiag(self,X,target): - """Compute the diagonal of the covariance matrix associated to X.""" - np.add(target,self.variance,target) - - def _param_grad_helper(self,dL_dK,X,X2,target): - """derivative of the covariance matrix with respect to the parameters.""" - if X2 is None: X2 = X - dist = np.sqrt(np.sum(np.square((X[:,None,:]-X2[None,:,:])/self.lengthscale),-1)) - invdist = 1./np.where(dist!=0.,dist,np.inf) - dist2M = np.square(X[:,None,:]-X2[None,:,:])/self.lengthscale**3 - dvar = (1+np.sqrt(5.)*dist+5./3*dist**2)*np.exp(-np.sqrt(5.)*dist) - dl = (self.variance * 5./3 * dist * (1 + np.sqrt(5.)*dist ) * np.exp(-np.sqrt(5.)*dist))[:,:,np.newaxis] * dist2M*invdist[:,:,np.newaxis] - target[0] += np.sum(dvar*dL_dK) - if self.ARD: - dl = (self.variance * 5./3 * dist * (1 + np.sqrt(5.)*dist ) * np.exp(-np.sqrt(5.)*dist))[:,:,np.newaxis] * dist2M*invdist[:,:,np.newaxis] - #dl = (self.variance* 3 * dist * np.exp(-np.sqrt(3.)*dist))[:,:,np.newaxis] * dist2M*invdist[:,:,np.newaxis] - target[1:] += (dl*dL_dK[:,:,None]).sum(0).sum(0) - else: - dl = (self.variance * 5./3 * dist * (1 + np.sqrt(5.)*dist ) * np.exp(-np.sqrt(5.)*dist)) * dist2M.sum(-1)*invdist - #dl = (self.variance* 3 * dist * np.exp(-np.sqrt(3.)*dist)) * dist2M.sum(-1)*invdist - target[1] += np.sum(dl*dL_dK) - - def dKdiag_dtheta(self,dL_dKdiag,X,target): - """derivative of the diagonal of the covariance matrix with respect to the parameters.""" - target[0] += np.sum(dL_dKdiag) - - def gradients_X(self,dL_dK,X,X2,target): - """derivative of the covariance matrix with respect to X.""" - if X2 is None: - dist = np.sqrt(np.sum(np.square((X[:,None,:]-X[None,:,:])/self.lengthscale),-1))[:,:,None] - ddist_dX = 2*(X[:,None,:]-X[None,:,:])/self.lengthscale**2/np.where(dist!=0.,dist,np.inf) - else: - dist = np.sqrt(np.sum(np.square((X[:,None,:]-X2[None,:,:])/self.lengthscale),-1))[:,:,None] - ddist_dX = (X[:,None,:]-X2[None,:,:])/self.lengthscale**2/np.where(dist!=0.,dist,np.inf) - gradients_X = - np.transpose(self.variance*5./3*dist*(1+np.sqrt(5)*dist)*np.exp(-np.sqrt(5)*dist)*ddist_dX,(1,0,2)) - target += np.sum(gradients_X*dL_dK.T[:,:,None],0) - - def dKdiag_dX(self,dL_dKdiag,X,target): - pass - - def Gram_matrix(self,F,F1,F2,F3,lower,upper): - """ - Return the Gram matrix of the vector of functions F with respect to the RKHS norm. The use of this function is limited to input_dim=1. - - :param F: vector of functions - :type F: np.array - :param F1: vector of derivatives of F - :type F1: np.array - :param F2: vector of second derivatives of F - :type F2: np.array - :param F3: vector of third derivatives of F - :type F3: np.array - :param lower,upper: boundaries of the input domain - :type lower,upper: floats - """ - assert self.input_dim == 1 - def L(x,i): - return(5*np.sqrt(5)/self.lengthscale**3*F[i](x) + 15./self.lengthscale**2*F1[i](x)+ 3*np.sqrt(5)/self.lengthscale*F2[i](x) + F3[i](x)) - n = F.shape[0] - G = np.zeros((n,n)) - for i in range(n): - for j in range(i,n): - G[i,j] = G[j,i] = integrate.quad(lambda x : L(x,i)*L(x,j),lower,upper)[0] - G_coef = 3.*self.lengthscale**5/(400*np.sqrt(5)) - Flower = np.array([f(lower) for f in F])[:,None] - F1lower = np.array([f(lower) for f in F1])[:,None] - F2lower = np.array([f(lower) for f in F2])[:,None] - orig = 9./8*np.dot(Flower,Flower.T) + 9.*self.lengthscale**4/200*np.dot(F2lower,F2lower.T) - orig2 = 3./5*self.lengthscale**2 * ( np.dot(F1lower,F1lower.T) + 1./8*np.dot(Flower,F2lower.T) + 1./8*np.dot(F2lower,Flower.T)) - return(1./self.variance* (G_coef*G + orig + orig2)) - - - diff --git a/GPy/kern/_src/coregionalize.py b/GPy/kern/_src/coregionalize.py index 69fc27ef..74cd2a1d 100644 --- a/GPy/kern/_src/coregionalize.py +++ b/GPy/kern/_src/coregionalize.py @@ -5,6 +5,7 @@ from kern import Kern import numpy as np from scipy import weave from ...core.parameterization import Param +from ...core.parameterization.transformations import Logexp class Coregionalize(Kern): """ @@ -20,7 +21,7 @@ class Coregionalize(Kern): k_2(x, y)=\mathbf{B} k(x, y) it is obtained as the tensor product between a covariance function - k(x,y) and B. + k(x, y) and B. :param output_dim: number of outputs to coregionalize :type output_dim: int @@ -29,7 +30,7 @@ class Coregionalize(Kern): :param W: a low rank matrix that determines the correlations between the different outputs, together with kappa it forms the coregionalization matrix B :type W: numpy array of dimensionality (num_outpus, W_columns) :param kappa: a vector which allows the outputs to behave independently - :type kappa: numpy array of dimensionality (output_dim,) + :type kappa: numpy array of dimensionality (output_dim, ) .. note: see coregionalization examples in GPy.examples.regression for some usage. """ @@ -37,18 +38,18 @@ class Coregionalize(Kern): super(Coregionalize, self).__init__(input_dim=1, name=name) self.output_dim = output_dim self.rank = rank - if self.rank>output_dim-1: + if self.rank>output_dim: print("Warning: Unusual choice of rank, it should normally be less than the output_dim.") if W is None: - W = 0.5*np.random.randn(self.output_dim,self.rank)/np.sqrt(self.rank) + W = 0.5*np.random.randn(self.output_dim, self.rank)/np.sqrt(self.rank) else: - assert W.shape==(self.output_dim,self.rank) - self.W = Param('W',W) + assert W.shape==(self.output_dim, self.rank) + self.W = Param('W', W) if kappa is None: kappa = 0.5*np.ones(self.output_dim) else: - assert kappa.shape==(self.output_dim,) - self.kappa = Param('kappa', kappa) + assert kappa.shape==(self.output_dim, ) + self.kappa = Param('kappa', kappa, Logexp()) self.add_parameters(self.W, self.kappa) self.parameters_changed() @@ -56,54 +57,58 @@ class Coregionalize(Kern): def parameters_changed(self): self.B = np.dot(self.W, self.W.T) + np.diag(self.kappa) - def K(self,index,index2,target): - index = np.asarray(index,dtype=np.int) + def K(self, X, X2=None): + index = np.asarray(X, dtype=np.int) #here's the old code (numpy) #if index2 is None: #index2 = index #else: - #index2 = np.asarray(index2,dtype=np.int) + #index2 = np.asarray(index2, dtype=np.int) #false_target = target.copy() - #ii,jj = np.meshgrid(index,index2) - #ii,jj = ii.T, jj.T - #false_target += self.B[ii,jj] + #ii, jj = np.meshgrid(index, index2) + #ii, jj = ii.T, jj.T + #false_target += self.B[ii, jj] - if index2 is None: + + if X2 is None: + target = np.empty((X.shape[0], X.shape[0]), dtype=np.float64) code=""" for(int i=0;i>> import numpy as np >>> X = np.arange(9).reshape(3,3) >>> view(X) @@ -36,7 +36,7 @@ def view(A, offset=0): """ from numpy.lib.stride_tricks import as_strided assert A.ndim == 2, "only implemented for 2 dimensions" - assert A.shape[0] == A.shape[1], "attempting to get the view of non-square matrix?!" + assert A.shape[0] == A.shape[1], "attempting to get the view of non-square matrix?!" if offset > 0: return as_strided(A[0, offset:], shape=(A.shape[0] - offset, ), strides=((A.shape[0]+1)*A.itemsize, )) elif offset < 0: @@ -44,6 +44,12 @@ def view(A, offset=0): else: return as_strided(A, shape=(A.shape[0], ), strides=((A.shape[0]+1)*A.itemsize, )) +def offdiag_view(A, offset=0): + from numpy.lib.stride_tricks import as_strided + assert A.ndim == 2, "only implemented for 2 dimensions" + Af = as_strided(A, shape=(A.size,), strides=(A.itemsize,)) + return as_strided(Af[(1+offset):], shape=(A.shape[0]-1, A.shape[1]), strides=(A.strides[0] + A.itemsize, A.strides[1])) + def _diag_ufunc(A,b,offset,func): dA = view(A, offset); func(dA,b,dA) return A @@ -51,11 +57,11 @@ def _diag_ufunc(A,b,offset,func): def times(A, b, offset=0): """ Times the view of A with b in place (!). - Returns modified A + Returns modified A Broadcasting is allowed, thus b can be scalar. - + if offset is not zero, make sure b is of right shape! - + :param ndarray A: 2 dimensional array :param ndarray-like b: either one dimensional or scalar :param int offset: same as in view. @@ -67,11 +73,11 @@ multiply = times def divide(A, b, offset=0): """ Divide the view of A by b in place (!). - Returns modified A + Returns modified A Broadcasting is allowed, thus b can be scalar. - + if offset is not zero, make sure b is of right shape! - + :param ndarray A: 2 dimensional array :param ndarray-like b: either one dimensional or scalar :param int offset: same as in view. @@ -84,9 +90,9 @@ def add(A, b, offset=0): Add b to the view of A in place (!). Returns modified A. Broadcasting is allowed, thus b can be scalar. - + if offset is not zero, make sure b is of right shape! - + :param ndarray A: 2 dimensional array :param ndarray-like b: either one dimensional or scalar :param int offset: same as in view. @@ -99,16 +105,16 @@ def subtract(A, b, offset=0): Subtract b from the view of A in place (!). Returns modified A. Broadcasting is allowed, thus b can be scalar. - + if offset is not zero, make sure b is of right shape! - + :param ndarray A: 2 dimensional array :param ndarray-like b: either one dimensional or scalar :param int offset: same as in view. :rtype: view of A, which is adjusted inplace """ return _diag_ufunc(A, b, offset, np.subtract) - + if __name__ == '__main__': import doctest - doctest.testmod() \ No newline at end of file + doctest.testmod()