diff --git a/GPy/core/parameterization/param.py b/GPy/core/parameterization/param.py index 324593f9..b73e7dfa 100644 --- a/GPy/core/parameterization/param.py +++ b/GPy/core/parameterization/param.py @@ -226,7 +226,7 @@ class Param(OptimizationHandlable, ObsAr): # Constrainable #=========================================================================== def _ensure_fixes(self): - self._fixes_ = numpy.ones(self._realsize_, dtype=bool) + if not self._has_fixes(): self._fixes_ = numpy.ones(self._realsize_, dtype=bool) #=========================================================================== # Convenience diff --git a/GPy/core/parameterization/parameter_core.py b/GPy/core/parameterization/parameter_core.py index 0aab890c..d4779127 100644 --- a/GPy/core/parameterization/parameter_core.py +++ b/GPy/core/parameterization/parameter_core.py @@ -16,7 +16,7 @@ Observable Pattern for patameterization from transformations import Transformation, Logexp, NegativeLogexp, Logistic, __fixed__, FIXED, UNFIXED import numpy as np -__updated__ = '2014-03-17' +__updated__ = '2014-03-18' class HierarchyError(Exception): """ @@ -377,7 +377,7 @@ class Constrainable(Nameable, Indexable): # Ensure that the fixes array is set: # Parameterized: ones(self.size) # Param: ones(self._realsize_ - self._fixes_ = np.ones(self.size, dtype=bool) + if not self._has_fixes(): self._fixes_ = np.ones(self.size, dtype=bool) def _set_fixed(self, index): self._ensure_fixes() @@ -398,7 +398,7 @@ class Constrainable(Nameable, Indexable): self._fixes_ = None def _has_fixes(self): - return hasattr(self, "_fixes_") and self._fixes_ is not None + return hasattr(self, "_fixes_") and self._fixes_ is not None and self._fixes_.size == self.size #=========================================================================== # Prior Operations @@ -576,14 +576,22 @@ class OptimizationHandlable(Constrainable): # transformed parameters (apply transformation rules) p = self._param_array_.copy() [np.put(p, ind, c.finv(p[ind])) for c, ind in self.constraints.iteritems() if c != __fixed__] - if self._has_fixes(): + if self.has_parent() and self.constraints[__fixed__].size != 0: + fixes = np.ones(self.size).astype(bool) + fixes[self.constraints[__fixed__]] = FIXED + return p[fixes] + elif self._has_fixes(): return p[self._fixes_] return p def _set_params_transformed(self, p): if p is self._param_array_: p = p.copy() - if self._has_fixes(): self._param_array_[self._fixes_] = p + if self.has_parent() and self.constraints[__fixed__].size != 0: + fixes = np.ones(self.size).astype(bool) + fixes[self.constraints[__fixed__]] = FIXED + self._param_array_[fixes] = p + elif self._has_fixes(): self._param_array_[self._fixes_] = p else: self._param_array_[:] = p self.untransform() self._trigger_params_changed() @@ -770,11 +778,11 @@ class Parameterizable(OptimizationHandlable): Add all parameters to this param class, you can insert parameters at any given index using the :func:`list.insert` syntax """ - # if param.has_parent(): - # raise AttributeError, "parameter {} already in another model, create new object (or copy) for adding".format(param._short()) if param in self._parameters_ and index is not None: self.remove_parameter(param) self.add_parameter(param, index) + elif param.has_parent(): + raise HierarchyError, "parameter {} already in another model ({}), create new object (or copy) for adding".format(param._short(), param._highest_parent_._short()) elif param not in self._parameters_: if param.has_parent(): parent = param._parent_ @@ -798,13 +806,19 @@ class Parameterizable(OptimizationHandlable): param.add_observer(self, self._pass_through_notify_observers, -np.inf) - self.size += param.size + parent = self + while parent is not None: + parent.size += param.size + parent = parent._parent_ + + self._connect_parameters() + + self._highest_parent_._connect_parameters(ignore_added_names=_ignore_added_names) + self._highest_parent_._notify_parent_change() + self._highest_parent_._connect_fixes() - self._connect_parameters(ignore_added_names=_ignore_added_names) - self._notify_parent_change() - self._connect_fixes() else: - raise RuntimeError, """Parameter exists already added and no copy made""" + raise HierarchyError, """Parameter exists already and no copy made""" def add_parameters(self, *parameters): @@ -830,17 +844,18 @@ class Parameterizable(OptimizationHandlable): param.remove_observer(self, self._pass_through_notify_observers) self.constraints.shift_left(start, param.size) - self._connect_fixes() self._connect_parameters() self._notify_parent_change() parent = self._parent_ while parent is not None: - parent._connect_fixes() - parent._connect_parameters() - parent._notify_parent_change() + parent.size -= param.size parent = parent._parent_ + self._highest_parent_._connect_parameters() + self._highest_parent_._connect_fixes() + self._highest_parent_._notify_parent_change() + def _connect_parameters(self, ignore_added_names=False): # connect parameterlist to this parameterized object # This just sets up the right connection for the params objects diff --git a/GPy/testing/parameterized_tests.py b/GPy/testing/parameterized_tests.py index 81c2dfdd..cd5127c8 100644 --- a/GPy/testing/parameterized_tests.py +++ b/GPy/testing/parameterized_tests.py @@ -34,9 +34,9 @@ class ParameterizedTest(unittest.TestCase): self.param = Param('param', np.random.rand(25,2), Logistic(0, 1)) self.test1 = GPy.core.Parameterized("test model") - self.test1.add_parameter(self.white) - self.test1.add_parameter(self.rbf, 0) - self.test1.add_parameter(self.param) + self.test1.kern = self.rbf+self.white + self.test1.add_parameter(self.test1.kern) + self.test1.add_parameter(self.param, 0) x = np.linspace(-2,6,4)[:,None] y = np.sin(x) @@ -45,22 +45,24 @@ class ParameterizedTest(unittest.TestCase): def test_add_parameter(self): self.assertEquals(self.rbf._parent_index_, 0) self.assertEquals(self.white._parent_index_, 1) + self.assertEquals(self.param._parent_index_, 0) pass def test_fixes(self): self.white.fix(warning=False) - self.test1.remove_parameter(self.test1.param) + self.test1.remove_parameter(self.param) self.assertTrue(self.test1._has_fixes()) from GPy.core.parameterization.transformations import FIXED, UNFIXED self.assertListEqual(self.test1._fixes_.tolist(),[UNFIXED,UNFIXED,FIXED]) - - self.test1.add_parameter(self.white, 0) + self.test1.kern.add_parameter(self.white, 0) self.assertListEqual(self.test1._fixes_.tolist(),[FIXED,UNFIXED,UNFIXED]) + self.test1.kern.rbf.fix() + self.assertListEqual(self.test1._fixes_.tolist(),[FIXED]*3) def test_remove_parameter(self): from GPy.core.parameterization.transformations import FIXED, UNFIXED, __fixed__, Logexp self.white.fix() - self.test1.remove_parameter(self.white) + self.test1.kern.remove_parameter(self.white) self.assertIs(self.test1._fixes_,None) self.assertListEqual(self.white._fixes_.tolist(), [FIXED]) @@ -81,7 +83,12 @@ class ParameterizedTest(unittest.TestCase): self.assertListEqual(self.white._fixes_.tolist(), [FIXED]) self.assertIs(self.test1.constraints, self.rbf.constraints._param_index_ops) self.assertIs(self.test1.constraints, self.param.constraints._param_index_ops) - self.assertListEqual(self.test1.constraints[Logexp()].tolist(), [0,1]) + self.assertListEqual(self.test1.constraints[Logexp()].tolist(), range(self.param.size, self.param.size+self.rbf.size)) + + def test_remove_parameter_param_array_grad_array(self): + val = self.test1.kern._param_array_.copy() + self.test1.kern.remove_parameter(self.white) + self.assertListEqual(self.test1.kern._param_array_.tolist(), val[:2].tolist()) def test_add_parameter_already_in_hirarchy(self): self.assertRaises(HierarchyError, self.test1.add_parameter, self.white._parameters_[0]) @@ -91,28 +98,35 @@ class ParameterizedTest(unittest.TestCase): self.assertIs(self.test1.constraints, self.rbf.constraints._param_index_ops) self.assertListEqual(self.rbf.constraints.indices()[0].tolist(), range(2)) from GPy.core.parameterization.transformations import Logexp - kern = self.rbf+self.white + kern = self.test1.kern + self.test1.remove_parameter(kern) self.assertListEqual(kern.constraints[Logexp()].tolist(), range(3)) def test_constraints(self): self.rbf.constrain(GPy.transformations.Square(), False) - self.assertListEqual(self.test1.constraints[GPy.transformations.Square()].tolist(), range(2)) - self.assertListEqual(self.test1.constraints[GPy.transformations.Logexp()].tolist(), [2]) + self.assertListEqual(self.test1.constraints[GPy.transformations.Square()].tolist(), range(self.param.size, self.param.size+self.rbf.size)) + self.assertListEqual(self.test1.constraints[GPy.transformations.Logexp()].tolist(), [self.param.size+self.rbf.size]) - self.test1.remove_parameter(self.rbf) + self.test1.kern.remove_parameter(self.rbf) self.assertListEqual(self.test1.constraints[GPy.transformations.Square()].tolist(), []) def test_constraints_views(self): - self.assertEqual(self.white.constraints._offset, 2) - self.assertEqual(self.rbf.constraints._offset, 0) - self.assertEqual(self.param.constraints._offset, 3) + self.assertEqual(self.white.constraints._offset, self.param.size+self.rbf.size) + self.assertEqual(self.rbf.constraints._offset, self.param.size) + self.assertEqual(self.param.constraints._offset, 0) def test_fixing_randomize(self): self.white.fix(warning=True) - val = float(self.test1.white.variance) + val = float(self.white.variance) self.test1.randomize() self.assertEqual(val, self.white.variance) + def test_fixing_randomize_parameter_handling(self): + self.rbf.fix(warning=True) + val = float(self.rbf.variance) + self.test1.kern.randomize() + self.assertEqual(val, self.rbf.variance) + def test_fixing_optimize(self): self.testmodel.kern.lengthscale.fix() val = float(self.testmodel.kern.lengthscale)