From f2ce47d96e5704ab4e54666ce75ff3201c8ff84e Mon Sep 17 00:00:00 2001 From: James Hensman Date: Tue, 5 Mar 2013 15:58:03 +0000 Subject: [PATCH] Added symmtrical covariance functions --- GPy/kern/__init__.py | 2 +- GPy/kern/constructors.py | 10 +++++ GPy/kern/symmetric.py | 92 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 GPy/kern/symmetric.py diff --git a/GPy/kern/__init__.py b/GPy/kern/__init__.py index 008a2e1a..3e20644b 100644 --- a/GPy/kern/__init__.py +++ b/GPy/kern/__init__.py @@ -2,5 +2,5 @@ # Licensed under the BSD 3-clause license (see LICENSE.txt) -from constructors import rbf, Matern32, Matern52, exponential, linear, white, bias, finite_dimensional, spline, Brownian, rbf_sympy, sympykern, periodic_exponential, periodic_Matern32, periodic_Matern52, product, product_orthogonal +from constructors import rbf, Matern32, Matern52, exponential, linear, white, bias, finite_dimensional, spline, Brownian, rbf_sympy, sympykern, periodic_exponential, periodic_Matern32, periodic_Matern52, product, product_orthogonal, symmetric from kern import kern diff --git a/GPy/kern/constructors.py b/GPy/kern/constructors.py index af82bb24..5d665d93 100644 --- a/GPy/kern/constructors.py +++ b/GPy/kern/constructors.py @@ -20,6 +20,7 @@ from periodic_Matern32 import periodic_Matern32 as periodic_Matern32part from periodic_Matern52 import periodic_Matern52 as periodic_Matern52part from product import product as productpart from product_orthogonal import product_orthogonal as product_orthogonalpart +from symmetric import symmetric as symmetric_part #TODO these s=constructors are not as clean as we'd like. Tidy the code up #using meta-classes to make the objects construct properly wthout them. @@ -264,3 +265,12 @@ def product_orthogonal(k1,k2): """ part = product_orthogonalpart(k1,k2) return kern(k1.D+k2.D, [part]) + +def symmetric(k): + """ + Construct a symmetrical kernel from an existing kernel + """ + k_ = k.copy() + k_.parts = [symmetric_part(p) for p in k.parts] + return k_ + diff --git a/GPy/kern/symmetric.py b/GPy/kern/symmetric.py new file mode 100644 index 00000000..d493bfb1 --- /dev/null +++ b/GPy/kern/symmetric.py @@ -0,0 +1,92 @@ +# Copyright (c) 2012 James Hensman +# Licensed under the BSD 3-clause license (see LICENSE.txt) + +from kernpart import kernpart +import numpy as np + +class symmetric(kernpart): + """ + Symmetrical kernels + + :param k: the kernel to symmetrify + :type k: kernpart + :param transform: the transform to use in symmetrification (allows symmetry on specified axes) + :type transform: A numpy array (D x D) specifiying the transform + :rtype: kernpart + + """ + def __init__(self,k,transform=None): + if transform is None: + transform = np.eye(k.D)*-1. + assert transform.shape == (k.D, k.D) + self.transform = transform + self.D = k.D + self.Nparam = k.Nparam + self.name = k.name + '_symm' + self.k = k + self._set_params(k._get_params()) + + def _get_params(self): + """return the value of the parameters.""" + return self.k._get_params() + + def _set_params(self,x): + """set the value of the parameters.""" + self.k._set_params(x) + + def _get_param_names(self): + """return parameter names.""" + return self.k._get_param_names() + + def K(self,X,X2,target): + """Compute the covariance matrix between X and X2.""" + AX = np.dot(X,self.transform) + if X2 is None: + X2 = X + AX2 = AX + else: + AX2 = np.dot(X2, self.transform) + self.k.K(X,X2,target) + self.k.K(AX,X2,target) + self.k.K(X,AX2,target) + self.k.K(AX,AX2,target) + + def dK_dtheta(self,partial,X,X2,target): + """derivative of the covariance matrix with respect to the parameters.""" + AX = np.dot(X,self.transform) + if X2 is None: + X2 = X + ZX2 = AX + else: + AX2 = np.dot(X2, self.transform) + self.k.dK_dtheta(partial,X,X2,target) + self.k.dK_dtheta(partial,AX,X2,target) + self.k.dK_dtheta(partial,X,AX2,target) + self.k.dK_dtheta(partial,AX,AX2,target) + + + def dK_dX(self,partial,X,X2,target): + """derivative of the covariance matrix with respect to X.""" + AX = np.dot(X,self.transform) + if X2 is None: + X2 = X + ZX2 = AX + else: + AX2 = np.dot(X2, self.transform) + self.k.dK_dX(partial, X, X2, target) + self.k.dK_dX(partial, AX, X2, target) + self.k.dK_dX(partial, X, AX2, target) + self.k.dK_dX(partial, AX ,AX2, target) + + def Kdiag(self,X,target): + """Compute the diagonal of the covariance matrix associated to X.""" + foo = np.zeros((X.shape[0],X.shape[0])) + self.K(X,X,foo) + target += np.diag(foo) + + def dKdiag_dX(self,partial,X,target): + raise NotImplementedError + + def dKdiag_dtheta(self,partial,X,target): + """Compute the diagonal of the covariance matrix associated to X.""" + raise NotImplementedError