diff --git a/GPy/kern/_src/independent_outputs.py b/GPy/kern/_src/independent_outputs.py index 3493cf4f..12c51ca3 100644 --- a/GPy/kern/_src/independent_outputs.py +++ b/GPy/kern/_src/independent_outputs.py @@ -32,7 +32,7 @@ def index_to_slices(index): [ret[ind_i].append(slice(*indexes_i)) for ind_i,indexes_i in zip(ind[switchpoints[:-1]],zip(switchpoints,switchpoints[1:]))] return ret -class IndependentOutputs(Kern): +class IndependentOutputs(CombinationKernel): """ A kernel which can represent several independent functions. this kernel 'switches off' parts of the matrix where the output indexes are different. diff --git a/GPy/kern/_src/kern.py b/GPy/kern/_src/kern.py index 70bd42b9..4028e16b 100644 --- a/GPy/kern/_src/kern.py +++ b/GPy/kern/_src/kern.py @@ -45,7 +45,7 @@ class Kern(Parameterized): try: self.input_dim = int(input_dim) self.active_dims = active_dims# if active_dims is not None else slice(0, input_dim, 1) - except TypeError: + except ValueError: # input_dim is something else then an integer self.input_dim = input_dim if active_dims is not None: @@ -202,12 +202,12 @@ class Kern(Parameterized): return Prod([self, other], name) def _check_input_dim(self, X): - assert X.shape[1] == self.input_dim, "You did not specify active_dims and X has wrong shape: X_dim={}, whereas input_dim={}".format(X.shape[1], self.input_dim) - + assert X.shape[1] == self.input_dim, "{} did not specify active_dims and X has wrong shape: X_dim={}, whereas input_dim={}".format(self.name, X.shape[1], self.input_dim) + def _check_active_dims(self, X): assert X.shape[1] >= len(np.r_[self.active_dims]), "At least {} dimensional X needed, X.shape={!s}".format(len(np.r_[self.active_dims]), X.shape) - + class CombinationKernel(Kern): """ Abstract super class for combination kernels. @@ -238,16 +238,16 @@ class CombinationKernel(Kern): def get_input_dim_active_dims(self, kernels, extra_dims = None): #active_dims = reduce(np.union1d, (np.r_[x.active_dims] for x in kernels), np.array([], dtype=int)) #active_dims = np.array(np.concatenate((active_dims, extra_dims if extra_dims is not None else [])), dtype=int) - input_dim = np.array([k.input_dim for k in kernels]) - if np.all(input_dim[0]==input_dim): - input_dim = input_dim[0] + input_dim = " ".join(map(lambda k: "{!s}:{!s}".format(k.name, k.input_dim), kernels)) + if extra_dims is not None: + input_dim += " + extra:{!s}".format(extra_dims) active_dims = None return input_dim, active_dims def input_sensitivity(self): raise NotImplementedError("Choose the kernel you want to get the sensitivity for. You need to override the default behaviour for getting the input sensitivity to be able to get the input sensitivity. For sum kernel it is the sum of all sensitivities, TODO: product kernel? Other kernels?, also TODO: shall we return all the sensitivities here in the combination kernel? So we can combine them however we want? This could lead to just plot all the sensitivities here...") - def _check_input_dim(self, X): + def _check_active_dims(self, X): return def _check_input_dim(self, X): diff --git a/GPy/testing/kernel_tests.py b/GPy/testing/kernel_tests.py index 5bd3f494..8c48d37f 100644 --- a/GPy/testing/kernel_tests.py +++ b/GPy/testing/kernel_tests.py @@ -319,7 +319,7 @@ class KernelTestsMiscellaneous(unittest.TestCase): GPy.kern.Kern(int(np.round((i+1)/j)), slice(0, i+1, j), "testkern") # test the ability to have only one dim sk = GPy.kern.RBF(2) + GPy.kern.Matern32(2) - self.assertEqual(sk.input_dim, 2) + self.assertEqual(sk.input_dim, "rbf:2 Mat32:2 + extra:[]") def test_which_parts(self): self.assertTrue(np.allclose(self.sumkern.K(self.X, which_parts=[self.linear, self.matern]), self.linear.K(self.X)+self.matern.K(self.X))) @@ -344,10 +344,15 @@ class KernelTestsNonContinuous(unittest.TestCase): self.X2[(N0*2):, -1] = 1 def test_IndependentOutputs(self): - k = GPy.kern.RBF(self.D) + k = GPy.kern.RBF(self.D, active_dims=range(self.D)) kern = GPy.kern.IndependentOutputs(k, -1, 'ind_single') self.assertTrue(check_kernel_gradient_functions(kern, X=self.X, X2=self.X2, verbose=verbose, fixed_X_dims=-1)) - k = [GPy.kern.RBF(1, active_dims=[1], name='rbf1'), GPy.kern.RBF(self.D, name='rbf012'), GPy.kern.RBF(2, active_dims=[0,2], name='rbf02')] + k = [GPy.kern.RBF(1, active_dims=[1], name='rbf1'), GPy.kern.RBF(self.D, active_dims=range(self.D), name='rbf012'), GPy.kern.RBF(2, active_dims=[0,2], name='rbf02')] + kern = GPy.kern.IndependentOutputs(k, -1, name='ind_split') + self.assertTrue(check_kernel_gradient_functions(kern, X=self.X, X2=self.X2, verbose=verbose, fixed_X_dims=-1)) + + def test_Hierarchical(self): + k = [GPy.kern.RBF(2, active_dims=[0,2], name='rbf1'), GPy.kern.RBF(2, active_dims=[0,2], name='rbf2')] kern = GPy.kern.IndependentOutputs(k, -1, name='ind_split') self.assertTrue(check_kernel_gradient_functions(kern, X=self.X, X2=self.X2, verbose=verbose, fixed_X_dims=-1))