From c0bed0269a859401bc266c99228ed02c781c0ca4 Mon Sep 17 00:00:00 2001 From: Michael T Smith Date: Tue, 6 Jun 2017 20:17:58 +0100 Subject: [PATCH] Fixing missing factor of sqrt(2) in lengthscale --- GPy/kern/src/integral.py | 14 +++++++++----- GPy/kern/src/integral_limits.py | 14 +++++++++----- GPy/kern/src/integral_output_observed.py | 14 +++++++++----- .../src/multidimensional_integral_limits.py | 18 ++++++++++++------ 4 files changed, 39 insertions(+), 21 deletions(-) diff --git a/GPy/kern/src/integral.py b/GPy/kern/src/integral.py index 6febf203..df362fd8 100644 --- a/GPy/kern/src/integral.py +++ b/GPy/kern/src/integral.py @@ -27,8 +27,9 @@ class Integral(Kern): #todo do I need to inherit from Stationary def h(self, z): return 0.5 * z * np.sqrt(math.pi) * math.erf(z) + np.exp(-(z**2)) - def dk_dl(self, t, tprime, l): #derivative of the kernel wrt lengthscale - return l * ( self.h(t/l) - self.h((t - tprime)/l) + self.h(tprime/l) - 1) + def dk_dl(self, t, tprime, lengthscale): #derivative of the kernel wrt lengthscale + l = lengthscale * np.sqrt(2) + return np.sqrt(2) * l * ( self.h(t/l) - self.h((t - tprime)/l) + self.h(tprime/l) - 1) def update_gradients_full(self, dL_dK, X, X2=None): if X2 is None: #we're finding dK_xx/dTheta @@ -48,14 +49,17 @@ class Integral(Kern): #todo do I need to inherit from Stationary return 1.0 * z * np.sqrt(math.pi) * math.erf(z) + np.exp(-(z**2)) #covariance between gradients (it's the gradients that we want out... maybe we should have a way of getting K_ff too? Currently you get the diag of K_ff from Kdiag) - def k_xx(self,t,tprime,l): + def k_xx(self,t,tprime,lengthscale): + l = lengthscale * np.sqrt(2) return 0.5 * (l**2) * ( self.g(t/l) - self.g((t - tprime)/l) + self.g(tprime/l) - 1) - def k_ff(self,t,tprime,l): + def k_ff(self,t,tprime,lengthscale): + l = lengthscale * np.sqrt(2) return np.exp(-((t-tprime)**2)/(l**2)) #rbf #covariance between the gradient and the actual value - def k_xf(self,t,tprime,l): + def k_xf(self,t,tprime,lengthscale): + l = lengthscale * np.sqrt(2) return 0.5 * np.sqrt(math.pi) * l * (math.erf((t-tprime)/l) + math.erf(tprime/l)) def K(self, X, X2=None): diff --git a/GPy/kern/src/integral_limits.py b/GPy/kern/src/integral_limits.py index 10370328..0ff4005c 100644 --- a/GPy/kern/src/integral_limits.py +++ b/GPy/kern/src/integral_limits.py @@ -32,8 +32,9 @@ class Integral_Limits(Kern): def h(self, z): return 0.5 * z * np.sqrt(math.pi) * math.erf(z) + np.exp(-(z**2)) - def dk_dl(self, t, tprime, s, sprime, l): #derivative of the kernel wrt lengthscale - return l * ( self.h((t-sprime)/l) - self.h((t - tprime)/l) + self.h((tprime-s)/l) - self.h((s-sprime)/l)) + def dk_dl(self, t, tprime, s, sprime, lengthscale): #derivative of the kernel wrt lengthscale + l = lengthscale * np.sqrt(2) + return np.sqrt(2) * l * ( self.h((t-sprime)/l) - self.h((t - tprime)/l) + self.h((tprime-s)/l) - self.h((s-sprime)/l)) def update_gradients_full(self, dL_dK, X, X2=None): if X2 is None: #we're finding dK_xx/dTheta @@ -52,7 +53,7 @@ class Integral_Limits(Kern): def g(self,z): return 1.0 * z * np.sqrt(math.pi) * math.erf(z) + np.exp(-(z**2)) - def k_xx(self,t,tprime,s,sprime,l): + def k_xx(self,t,tprime,s,sprime,lengthscale): """Covariance between observed values. s and t are one domain of the integral (i.e. the integral between s and t) @@ -61,17 +62,20 @@ class Integral_Limits(Kern): We're interested in how correlated these two integrals are. Note: We've not multiplied by the variance, this is done in K.""" + l = lengthscale * np.sqrt(2) return 0.5 * (l**2) * ( self.g((t-sprime)/l) + self.g((tprime-s)/l) - self.g((t - tprime)/l) - self.g((s-sprime)/l)) - def k_ff(self,t,tprime,l): + def k_ff(self,t,tprime,lengthscale): """Doesn't need s or sprime as we're looking at the 'derivatives', so no domains over which to integrate are required""" + l = lengthscale * np.sqrt(2) return np.exp(-((t-tprime)**2)/(l**2)) #rbf - def k_xf(self,t,tprime,s,l): + def k_xf(self,t,tprime,s,lengthscale): """Covariance between the gradient (latent value) and the actual (observed) value. Note that sprime isn't actually used in this expression, presumably because the 'primes' are the gradient (latent) values which don't involve an integration, and thus there is no domain over which they're integrated, just a single value that we want.""" + l = lengthscale * np.sqrt(2) return 0.5 * np.sqrt(math.pi) * l * (math.erf((t-tprime)/l) + math.erf((tprime-s)/l)) def K(self, X, X2=None): diff --git a/GPy/kern/src/integral_output_observed.py b/GPy/kern/src/integral_output_observed.py index ec3707cb..c91d2896 100644 --- a/GPy/kern/src/integral_output_observed.py +++ b/GPy/kern/src/integral_output_observed.py @@ -36,8 +36,9 @@ class Integral_Output_Observed(Kern): #todo do I need to inherit from Stationary def h(self, z): return 0.5 * z * np.sqrt(math.pi) * math.erf(z) + np.exp(-(z**2)) - def dk_dl(self, t, tprime, s, sprime, l): #derivative of the kernel wrt lengthscale - return l * ( self.h((t-sprime)/l) - self.h((t - tprime)/l) + self.h((tprime-s)/l) - self.h((s-sprime)/l)) + def dk_dl(self, t, tprime, s, sprime, lengthscale): #derivative of the kernel wrt lengthscale + l = lengthscale * np.sqrt(2) + return np.sqrt(2) * l * ( self.h((t-sprime)/l) - self.h((t - tprime)/l) + self.h((tprime-s)/l) - self.h((s-sprime)/l)) def update_gradients_full(self, dL_dK, X, X2=None): if X2 is None: #we're finding dK_xx/dTheta @@ -68,7 +69,7 @@ class Integral_Output_Observed(Kern): #todo do I need to inherit from Stationary def g(self,z): return 1.0 * z * np.sqrt(math.pi) * math.erf(z) + np.exp(-(z**2)) - def k_xx(self,t,tprime,s,sprime,l): + def k_xx(self,t,tprime,s,sprime,lengthscale): """Covariance between observed values. s and t are one domain of the integral (i.e. the integral between s and t) @@ -77,17 +78,20 @@ class Integral_Output_Observed(Kern): #todo do I need to inherit from Stationary We're interested in how correlated these two integrals are. Note: We've not multiplied by the variance, this is done in K.""" + l = lengthscale * np.sqrt(2) return 0.5 * (l**2) * ( self.g((t-sprime)/l) + self.g((tprime-s)/l) - self.g((t - tprime)/l) - self.g((s-sprime)/l)) - def k_ff(self,t,tprime,l): + def k_ff(self,t,tprime,lengthscale): """Doesn't need s or sprime as we're looking at the 'derivatives', so no domains over which to integrate are required""" + l = lengthscale * np.sqrt(2) return np.exp(-((t-tprime)**2)/(l**2)) #rbf - def k_xf(self,t,tprime,s,l): + def k_xf(self,t,tprime,s,lengthscale): """Covariance between the gradient (latent value) and the actual (observed) value. Note that sprime isn't actually used in this expression, presumably because the 'primes' are the gradient (latent) values which don't involve an integration, and thus there is no domain over which they're integrated, just a single value that we want.""" + l = lengthscale * np.sqrt(2) return 0.5 * np.sqrt(math.pi) * l * (math.erf((t-tprime)/l) + math.erf((tprime-s)/l)) def calc_K_xx_wo_variance(self,X): diff --git a/GPy/kern/src/multidimensional_integral_limits.py b/GPy/kern/src/multidimensional_integral_limits.py index 97d76c6d..316f4d3b 100644 --- a/GPy/kern/src/multidimensional_integral_limits.py +++ b/GPy/kern/src/multidimensional_integral_limits.py @@ -33,8 +33,11 @@ class Multidimensional_Integral_Limits(Kern): #todo do I need to inherit from St def h(self, z): return 0.5 * z * np.sqrt(math.pi) * math.erf(z) + np.exp(-(z**2)) - def dk_dl(self, t, tprime, s, sprime, l): #derivative of the kernel wrt lengthscale - return l * ( self.h((t-sprime)/l) - self.h((t - tprime)/l) + self.h((tprime-s)/l) - self.h((s-sprime)/l)) + def dk_dl(self, t, tprime, s, sprime, lengthscale): #derivative of the kernel wrt lengthscale + l = lengthscale * np.sqrt(2) + grad = l * ( self.h((t-sprime)/l) - self.h((t - tprime)/l) + self.h((tprime-s)/l) - self.h((s-sprime)/l)) + return grad * np.sqrt(2) + def update_gradients_full(self, dL_dK, X, X2=None): if X2 is None: #we're finding dK_xx/dTheta @@ -65,7 +68,7 @@ class Multidimensional_Integral_Limits(Kern): #todo do I need to inherit from St def g(self,z): return 1.0 * z * np.sqrt(math.pi) * math.erf(z) + np.exp(-(z**2)) - def k_xx(self,t,tprime,s,sprime,l): + def k_xx(self,t,tprime,s,sprime,lengthscale): """Covariance between observed values. s and t are one domain of the integral (i.e. the integral between s and t) @@ -74,17 +77,20 @@ class Multidimensional_Integral_Limits(Kern): #todo do I need to inherit from St We're interested in how correlated these two integrals are. Note: We've not multiplied by the variance, this is done in K.""" + l = lengthscale * np.sqrt(2) return 0.5 * (l**2) * ( self.g((t-sprime)/l) + self.g((tprime-s)/l) - self.g((t - tprime)/l) - self.g((s-sprime)/l)) - def k_ff(self,t,tprime,l): - """Doesn't need s or sprime as we're looking at the 'derivatives', so no domains over which to integrate are required""" + def k_ff(self,t,tprime,lengthscale): + """Doesn't need s or sprime as we're looking at the 'derivatives', so no domains over which to integrate are required""" + l = lengthscale * np.sqrt(2) return np.exp(-((t-tprime)**2)/(l**2)) #rbf - def k_xf(self,t,tprime,s,l): + def k_xf(self,t,tprime,s,lengthscale): """Covariance between the gradient (latent value) and the actual (observed) value. Note that sprime isn't actually used in this expression, presumably because the 'primes' are the gradient (latent) values which don't involve an integration, and thus there is no domain over which they're integrated, just a single value that we want.""" + l = lengthscale * np.sqrt(2) return 0.5 * np.sqrt(math.pi) * l * (math.erf((t-tprime)/l) + math.erf((tprime-s)/l)) def calc_K_xx_wo_variance(self,X):