Merge branch 'params' of github.com:SheffieldML/GPy into params

This commit is contained in:
James Hensman 2014-03-14 11:47:47 +00:00
commit a05232af24
21 changed files with 301 additions and 259 deletions

View file

@ -301,8 +301,7 @@ class Model(Parameterized):
denominator = (2 * np.dot(dx, gradient)) denominator = (2 * np.dot(dx, gradient))
global_ratio = (f1 - f2) / np.where(denominator==0., 1e-32, denominator) global_ratio = (f1 - f2) / np.where(denominator==0., 1e-32, denominator)
return np.abs(1. - global_ratio) < tolerance or np.abs(f1-f2).sum() + np.abs((2 * np.dot(dx, gradient))).sum() < tolerance
return np.abs(1. - global_ratio) < tolerance
else: else:
# check the gradient of each parameter individually, and do some pretty printing # check the gradient of each parameter individually, and do some pretty printing
try: try:

View file

@ -23,17 +23,16 @@ class ParameterIndexOperations(object):
if constraints is not None: if constraints is not None:
for t, i in constraints.iteritems(): for t, i in constraints.iteritems():
self.add(t, i) self.add(t, i)
def __getstate__(self): def __getstate__(self):
return self._properties#, self._reverse return self._properties
def __setstate__(self, state): def __setstate__(self, state):
self._properties = state[0] self._properties = state
# self._reverse = state[1]
def iteritems(self): def iteritems(self):
return self._properties.iteritems() return self._properties.iteritems()
def items(self): def items(self):
return self._properties.items() return self._properties.items()
@ -42,7 +41,7 @@ class ParameterIndexOperations(object):
def iterproperties(self): def iterproperties(self):
return self._properties.iterkeys() return self._properties.iterkeys()
def shift_right(self, start, size): def shift_right(self, start, size):
for ind in self.iterindices(): for ind in self.iterindices():
toshift = ind>=start toshift = ind>=start
@ -58,29 +57,26 @@ class ParameterIndexOperations(object):
ind[toshift] -= size ind[toshift] -= size
if ind.size != 0: self._properties[v] = ind if ind.size != 0: self._properties[v] = ind
else: del self._properties[v] else: del self._properties[v]
def clear(self): def clear(self):
self._properties.clear() self._properties.clear()
@property @property
def size(self): def size(self):
return reduce(lambda a,b: a+b.size, self.iterindices(), 0) return reduce(lambda a,b: a+b.size, self.iterindices(), 0)
def iterindices(self): def iterindices(self):
return self._properties.itervalues() return self._properties.itervalues()
def indices(self): def indices(self):
return self._properties.values() return self._properties.values()
def properties_for(self, index): def properties_for(self, index):
return vectorize(lambda i: [prop for prop in self.iterproperties() if i in self[prop]], otypes=[list])(index) return vectorize(lambda i: [prop for prop in self.iterproperties() if i in self[prop]], otypes=[list])(index)
def add(self, prop, indices): def add(self, prop, indices):
try: self._properties[prop] = combine_indices(self._properties[prop], indices)
self._properties[prop] = combine_indices(self._properties[prop], indices)
except KeyError:
self._properties[prop] = indices
def remove(self, prop, indices): def remove(self, prop, indices):
if prop in self._properties: if prop in self._properties:
diff = remove_indices(self[prop], indices) diff = remove_indices(self[prop], indices)
@ -91,22 +87,22 @@ class ParameterIndexOperations(object):
del self._properties[prop] del self._properties[prop]
return removed.astype(int) return removed.astype(int)
return numpy.array([]).astype(int) return numpy.array([]).astype(int)
def update(self, parameter_index_view, offset=0): def update(self, parameter_index_view, offset=0):
for i, v in parameter_index_view.iteritems(): for i, v in parameter_index_view.iteritems():
self.add(i, v+offset) self.add(i, v+offset)
def copy(self): def copy(self):
return ParameterIndexOperations(dict(self.iteritems())) return ParameterIndexOperations(dict(self.iteritems()))
def __getitem__(self, prop): def __getitem__(self, prop):
return self._properties[prop] return self._properties[prop]
def __str__(self, *args, **kwargs): def __str__(self, *args, **kwargs):
import pprint import pprint
return pprint.pformat(dict(self._properties)) return pprint.pformat(dict(self._properties))
def combine_indices(arr1, arr2): def combine_indices(arr1, arr2):
return numpy.union1d(arr1, arr2) return numpy.union1d(arr1, arr2)
@ -114,24 +110,22 @@ def remove_indices(arr, to_remove):
return numpy.setdiff1d(arr, to_remove, True) return numpy.setdiff1d(arr, to_remove, True)
def index_empty(index): def index_empty(index):
return numpy.size(index) == 0 return numpy.size(index) == 0
class ParameterIndexOperationsView(object): class ParameterIndexOperationsView(object):
def __init__(self, param_index_operations, offset, size): def __init__(self, param_index_operations, offset, size):
self._param_index_ops = param_index_operations self._param_index_ops = param_index_operations
self._offset = offset self._offset = offset
self._size = size self._size = size
def __getstate__(self): def __getstate__(self):
return [self._param_index_ops, self._offset, self._size] return [self._param_index_ops, self._offset, self._size]
def __setstate__(self, state): def __setstate__(self, state):
self._param_index_ops = state[0] self._param_index_ops = state[0]
self._offset = state[1] self._offset = state[1]
self._size = state[2] self._size = state[2]
def _filter_index(self, ind): def _filter_index(self, ind):
return ind[(ind >= self._offset) * (ind < (self._offset + self._size))] - self._offset return ind[(ind >= self._offset) * (ind < (self._offset + self._size))] - self._offset
@ -140,7 +134,7 @@ class ParameterIndexOperationsView(object):
for i, ind in self._param_index_ops.iteritems(): for i, ind in self._param_index_ops.iteritems():
ind2 = self._filter_index(ind) ind2 = self._filter_index(ind)
if ind2.size > 0: if ind2.size > 0:
yield i, ind2 yield i, ind2
def items(self): def items(self):
return [[i,v] for i,v in self.iteritems()] return [[i,v] for i,v in self.iteritems()]
@ -151,7 +145,7 @@ class ParameterIndexOperationsView(object):
def iterproperties(self): def iterproperties(self):
for i, _ in self.iteritems(): for i, _ in self.iteritems():
yield i yield i
def shift_right(self, start, size): def shift_right(self, start, size):
@ -161,7 +155,7 @@ class ParameterIndexOperationsView(object):
self._param_index_ops.shift_left(start+self._offset, size) self._param_index_ops.shift_left(start+self._offset, size)
self._offset -= size self._offset -= size
self._size -= size self._size -= size
def clear(self): def clear(self):
for i, ind in self.items(): for i, ind in self.items():
self._param_index_ops.remove(i, ind+self._offset) self._param_index_ops.remove(i, ind+self._offset)
@ -198,7 +192,7 @@ class ParameterIndexOperationsView(object):
def __getitem__(self, prop): def __getitem__(self, prop):
ind = self._filter_index(self._param_index_ops[prop]) ind = self._filter_index(self._param_index_ops[prop])
return ind return ind
def __str__(self, *args, **kwargs): def __str__(self, *args, **kwargs):
import pprint import pprint
return pprint.pformat(dict(self.iteritems())) return pprint.pformat(dict(self.iteritems()))
@ -206,8 +200,8 @@ class ParameterIndexOperationsView(object):
def update(self, parameter_index_view, offset=0): def update(self, parameter_index_view, offset=0):
for i, v in parameter_index_view.iteritems(): for i, v in parameter_index_view.iteritems():
self.add(i, v+offset) self.add(i, v+offset)
def copy(self): def copy(self):
return ParameterIndexOperations(dict(self.iteritems())) return ParameterIndexOperations(dict(self.iteritems()))
pass pass

View file

@ -5,21 +5,17 @@ Created on 27 Feb 2014
''' '''
from collections import defaultdict from collections import defaultdict
class DefaultArrayDict(defaultdict):
def __init__(self): def intarray_default_factory():
import numpy as np
return np.int_([])
class IntArrayDict(defaultdict):
def __init__(self, default_factory=None):
""" """
Default will be self._default, if not set otherwise Default will be self._default, if not set otherwise
""" """
defaultdict.__init__(self, self.default_factory) defaultdict.__init__(self, intarray_default_factory)
class SetDict(DefaultArrayDict):
def default_factory(self):
return set()
class IntArrayDict(DefaultArrayDict):
def default_factory(self):
import numpy as np
return np.int_([])
class ArrayList(list): class ArrayList(list):
""" """

View file

@ -49,9 +49,6 @@ class Param(OptimizationHandlable, ObservableArray):
obj._realshape_ = obj.shape obj._realshape_ = obj.shape
obj._realsize_ = obj.size obj._realsize_ = obj.size
obj._realndim_ = obj.ndim obj._realndim_ = obj.ndim
from lists_and_dicts import SetDict
obj._tied_to_me_ = SetDict()
obj._tied_to_ = []
obj._original_ = True obj._original_ = True
obj._gradient_array_ = numpy.zeros(obj.shape, dtype=numpy.float64) obj._gradient_array_ = numpy.zeros(obj.shape, dtype=numpy.float64)
return obj return obj
@ -80,13 +77,11 @@ class Param(OptimizationHandlable, ObservableArray):
self._parent_index_ = getattr(obj, '_parent_index_', None) self._parent_index_ = getattr(obj, '_parent_index_', None)
self._default_constraint_ = getattr(obj, '_default_constraint_', None) self._default_constraint_ = getattr(obj, '_default_constraint_', None)
self._current_slice_ = getattr(obj, '_current_slice_', None) self._current_slice_ = getattr(obj, '_current_slice_', None)
self._tied_to_me_ = getattr(obj, '_tied_to_me_', None)
self._tied_to_ = getattr(obj, '_tied_to_', None)
self._realshape_ = getattr(obj, '_realshape_', None) self._realshape_ = getattr(obj, '_realshape_', None)
self._realsize_ = getattr(obj, '_realsize_', None) self._realsize_ = getattr(obj, '_realsize_', None)
self._realndim_ = getattr(obj, '_realndim_', None) self._realndim_ = getattr(obj, '_realndim_', None)
self._original_ = getattr(obj, '_original_', None) self._original_ = getattr(obj, '_original_', None)
self._name = getattr(obj, 'name', None) self._name = getattr(obj, '_name', None)
self._gradient_array_ = getattr(obj, '_gradient_array_', None) self._gradient_array_ = getattr(obj, '_gradient_array_', None)
self.constraints = getattr(obj, 'constraints', None) self.constraints = getattr(obj, 'constraints', None)
self.priors = getattr(obj, 'priors', None) self.priors = getattr(obj, 'priors', None)
@ -106,10 +101,10 @@ class Param(OptimizationHandlable, ObservableArray):
#=========================================================================== #===========================================================================
# Pickling operations # Pickling operations
#=========================================================================== #===========================================================================
def __reduce_ex__(self): def __reduce__(self):
func, args, state = super(Param, self).__reduce__() func, args, state = super(Param, self).__reduce__()
return func, args, (state, return func, args, (state,
(self.name, (self._name,
self._parent_, self._parent_,
self._parent_index_, self._parent_index_,
self._default_constraint_, self._default_constraint_,
@ -117,16 +112,16 @@ class Param(OptimizationHandlable, ObservableArray):
self._realshape_, self._realshape_,
self._realsize_, self._realsize_,
self._realndim_, self._realndim_,
self._tied_to_me_, self.constraints,
self._tied_to_, self.priors
) )
) )
def __setstate__(self, state): def __setstate__(self, state):
super(Param, self).__setstate__(state[0]) super(Param, self).__setstate__(state[0])
state = list(state[1]) state = list(state[1])
self._tied_to_ = state.pop() self.priors = state.pop()
self._tied_to_me_ = state.pop() self.constraints = state.pop()
self._realndim_ = state.pop() self._realndim_ = state.pop()
self._realsize_ = state.pop() self._realsize_ = state.pop()
self._realshape_ = state.pop() self._realshape_ = state.pop()
@ -134,7 +129,7 @@ class Param(OptimizationHandlable, ObservableArray):
self._default_constraint_ = state.pop() self._default_constraint_ = state.pop()
self._parent_index_ = state.pop() self._parent_index_ = state.pop()
self._parent_ = state.pop() self._parent_ = state.pop()
self.name = state.pop() self._name = state.pop()
def copy(self, *args): def copy(self, *args):
constr = self.constraints.copy() constr = self.constraints.copy()
@ -180,21 +175,21 @@ class Param(OptimizationHandlable, ObservableArray):
#=========================================================================== #===========================================================================
# Index Operations: # Index Operations:
#=========================================================================== #===========================================================================
def _internal_offset(self): #def _internal_offset(self):
internal_offset = 0 # internal_offset = 0
extended_realshape = numpy.cumprod((1,) + self._realshape_[:0:-1])[::-1] # extended_realshape = numpy.cumprod((1,) + self._realshape_[:0:-1])[::-1]
for i, si in enumerate(self._current_slice_[:self._realndim_]): # for i, si in enumerate(self._current_slice_[:self._realndim_]):
if numpy.all(si == Ellipsis): # if numpy.all(si == Ellipsis):
continue # continue
if isinstance(si, slice): # if isinstance(si, slice):
a = si.indices(self._realshape_[i])[0] # a = si.indices(self._realshape_[i])[0]
elif isinstance(si, (list,numpy.ndarray,tuple)): # elif isinstance(si, (list,numpy.ndarray,tuple)):
a = si[0] # a = si[0]
else: a = si # else: a = si
if a < 0: # if a < 0:
a = self._realshape_[i] + a # a = self._realshape_[i] + a
internal_offset += a * extended_realshape[i] # internal_offset += a * extended_realshape[i]
return internal_offset # return internal_offset
def _raveled_index(self, slice_index=None): def _raveled_index(self, slice_index=None):
# return an index array on the raveled array, which is formed by the current_slice # return an index array on the raveled array, which is formed by the current_slice
@ -204,6 +199,9 @@ class Param(OptimizationHandlable, ObservableArray):
if ind.ndim < 2: ind = ind[:, None] if ind.ndim < 2: ind = ind[:, None]
return numpy.asarray(numpy.apply_along_axis(lambda x: numpy.sum(extended_realshape * x), 1, ind), dtype=int) return numpy.asarray(numpy.apply_along_axis(lambda x: numpy.sum(extended_realshape * x), 1, ind), dtype=int)
def _raveled_index_for(self, obj):
return self._raveled_index()
def _expand_index(self, slice_index=None): def _expand_index(self, slice_index=None):
# this calculates the full indexing arrays from the slicing objects given by get_item for _real..._ attributes # this calculates the full indexing arrays from the slicing objects given by get_item for _real..._ attributes
# it basically translates slices to their respective index arrays and turns negative indices around # it basically translates slices to their respective index arrays and turns negative indices around
@ -224,6 +222,11 @@ class Param(OptimizationHandlable, ObservableArray):
return numpy.r_[a] return numpy.r_[a]
return numpy.r_[:b] return numpy.r_[:b]
return itertools.imap(f, itertools.izip_longest(slice_index[:self._realndim_], self._realshape_, fillvalue=slice(self.size))) return itertools.imap(f, itertools.izip_longest(slice_index[:self._realndim_], self._realshape_, fillvalue=slice(self.size)))
#===========================================================================
# Constrainable
#===========================================================================
def _ensure_fixes(self):
if not self._has_fixes(): self._fixes_ = numpy.ones(self._realsize_, dtype=bool)
#=========================================================================== #===========================================================================
# Convenience # Convenience
@ -239,7 +242,6 @@ class Param(OptimizationHandlable, ObservableArray):
#round.__doc__ = numpy.round.__doc__ #round.__doc__ = numpy.round.__doc__
def _get_original(self, param): def _get_original(self, param):
return self return self
#=========================================================================== #===========================================================================
# Printing -> done # Printing -> done
#=========================================================================== #===========================================================================
@ -266,23 +268,11 @@ class Param(OptimizationHandlable, ObservableArray):
return [' '.join(map(lambda c: str(c[0]) if c[1].size == self._realsize_ else "{" + str(c[0]) + "}", self.priors.iteritems()))] return [' '.join(map(lambda c: str(c[0]) if c[1].size == self._realsize_ else "{" + str(c[0]) + "}", self.priors.iteritems()))]
@property @property
def _ties_str(self): def _ties_str(self):
return [t._short() for t in self._tied_to_] or [''] return ['']
def __repr__(self, *args, **kwargs): def __repr__(self, *args, **kwargs):
name = "\033[1m{x:s}\033[0;0m:\n".format( name = "\033[1m{x:s}\033[0;0m:\n".format(
x=self.hierarchy_name()) x=self.hierarchy_name())
return name + super(Param, self).__repr__(*args, **kwargs) return name + super(Param, self).__repr__(*args, **kwargs)
def _ties_for(self, rav_index):
# size = sum(p.size for p in self._tied_to_)
ties = numpy.empty(shape=(len(self._tied_to_), numpy.size(rav_index)), dtype=Param)
for i, tied_to in enumerate(self._tied_to_):
for t, ind in tied_to._tied_to_me_.iteritems():
if t._parent_index_ == self._parent_index_:
matches = numpy.where(rav_index[:, None] == t._raveled_index()[None, :])
tt_rav_index = tied_to._raveled_index()
ind_rav_matches = numpy.where(tt_rav_index == numpy.array(list(ind)))[0]
if len(ind) != 1: ties[i, matches[0][ind_rav_matches]] = numpy.take(tt_rav_index, matches[1], mode='wrap')[ind_rav_matches]
else: ties[i, matches[0]] = numpy.take(tt_rav_index, matches[1], mode='wrap')
return map(lambda a: sum(a, []), zip(*[[[tie.flatten()] if tx != None else [] for tx in t] for t, tie in zip(ties, self._tied_to_)]))
def _indices(self, slice_index=None): def _indices(self, slice_index=None):
# get a int-array containing all indices in the first axis. # get a int-array containing all indices in the first axis.
if slice_index is None: if slice_index is None:
@ -322,8 +312,8 @@ class Param(OptimizationHandlable, ObservableArray):
ravi = self._raveled_index(filter_) ravi = self._raveled_index(filter_)
if constr_matrix is None: constr_matrix = self.constraints.properties_for(ravi) if constr_matrix is None: constr_matrix = self.constraints.properties_for(ravi)
if prirs is None: prirs = self.priors.properties_for(ravi) if prirs is None: prirs = self.priors.properties_for(ravi)
if ties is None: ties = self._ties_for(ravi) if ties is None: ties = [['N/A']]*self.size
ties = [' '.join(map(lambda x: x._short(), t)) for t in ties] ties = [' '.join(map(lambda x: x, t)) for t in ties]
if lc is None: lc = self._max_len_names(constr_matrix, __constraints_name__) if lc is None: lc = self._max_len_names(constr_matrix, __constraints_name__)
if lx is None: lx = self._max_len_values() if lx is None: lx = self._max_len_values()
if li is None: li = self._max_len_index(indices) if li is None: li = self._max_len_index(indices)

View file

@ -16,7 +16,7 @@ Observable Pattern for patameterization
from transformations import Transformation, Logexp, NegativeLogexp, Logistic, __fixed__, FIXED, UNFIXED from transformations import Transformation, Logexp, NegativeLogexp, Logistic, __fixed__, FIXED, UNFIXED
import numpy as np import numpy as np
__updated__ = '2014-03-13' __updated__ = '2014-03-14'
class HierarchyError(Exception): class HierarchyError(Exception):
""" """
@ -31,7 +31,71 @@ def adjust_name_for_printing(name):
return name.replace(" ", "_").replace(".", "_").replace("-", "_m_").replace("+", "_p_").replace("!", "_I_").replace("**", "_xx_").replace("*", "_x_").replace("/", "_l_").replace("@",'_at_') return name.replace(" ", "_").replace(".", "_").replace("-", "_m_").replace("+", "_p_").replace("!", "_I_").replace("**", "_xx_").replace("*", "_x_").replace("/", "_l_").replace("@",'_at_')
return '' return ''
class Observable(object): class InterfacePickleFunctions(object):
def __init__(self, *a, **kw):
super(InterfacePickleFunctions, self).__init__()
def _getstate(self):
"""
Returns the state of this class in a memento pattern.
The state must be a list-like structure of all the fields
this class needs to run.
See python doc "pickling" (`__getstate__` and `__setstate__`) for details.
"""
raise NotImplementedError, "To be able to use pickling you need to implement this method"
def _setstate(self, state):
"""
Set the state (memento pattern) of this class to the given state.
Usually this is just the counterpart to _getstate, such that
an object is a copy of another when calling
copy = <classname>.__new__(*args,**kw)._setstate(<to_be_copied>._getstate())
See python doc "pickling" (`__getstate__` and `__setstate__`) for details.
"""
raise NotImplementedError, "To be able to use pickling you need to implement this method"
class Pickleable(object):
"""
Make an object pickleable (See python doc 'pickling').
This class allows for pickling support by Memento pattern.
_getstate returns a memento of the class, which gets pickled.
_setstate(<memento>) (re-)sets the state of the class to the memento
"""
def __init__(self, *a, **kw):
super(Pickleable, self).__init__()
#===========================================================================
# Pickling operations
#===========================================================================
def pickle(self, f, protocol=-1):
"""
:param f: either filename or open file object to write to.
if it is an open buffer, you have to make sure to close
it properly.
:param protocol: pickling protocol to use, python-pickle for details.
"""
import cPickle
if isinstance(f, str):
with open(f, 'w') as f:
cPickle.dump(self, f, protocol)
else:
cPickle.dump(self, f, protocol)
def __getstate__(self):
if self._has_get_set_state():
return self._getstate()
return self.__dict__
def __setstate__(self, state):
if self._has_get_set_state():
self._setstate(state)
# TODO: maybe parameters_changed() here?
return
self.__dict__ = state
def _has_get_set_state(self):
return '_getstate' in vars(self.__class__) and '_setstate' in vars(self.__class__)
class Observable(InterfacePickleFunctions):
""" """
Observable pattern for parameterization. Observable pattern for parameterization.
@ -41,7 +105,7 @@ class Observable(object):
""" """
_updated = True _updated = True
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(Observable, self).__init__() super(Observable, self).__init__(*args, **kwargs)
self._observer_callables_ = [] self._observer_callables_ = []
def add_observer(self, observer, callble, priority=0): def add_observer(self, observer, callble, priority=0):
@ -89,68 +153,16 @@ class Observable(object):
ins += 1 ins += 1
self._observer_callables_.insert(ins, (p, o, c)) self._observer_callables_.insert(ins, (p, o, c))
class Pickleable(object):
"""
Make an object pickleable (See python doc 'pickling').
This class allows for pickling support by Memento pattern.
_getstate returns a memento of the class, which gets pickled.
_setstate(<memento>) (re-)sets the state of the class to the memento
"""
#===========================================================================
# Pickling operations
#===========================================================================
def pickle(self, f, protocol=-1):
"""
:param f: either filename or open file object to write to.
if it is an open buffer, you have to make sure to close
it properly.
:param protocol: pickling protocol to use, python-pickle for details.
"""
import cPickle
if isinstance(f, str):
with open(f, 'w') as f:
cPickle.dump(self, f, protocol)
else:
cPickle.dump(self, f, protocol)
def __getstate__(self):
if self._has_get_set_state():
return self._getstate()
return self.__dict__
def __setstate__(self, state):
if self._has_get_set_state():
self._setstate(state)
# TODO: maybe parameters_changed() here?
return
self.__dict__ = state
def _has_get_set_state(self):
return '_getstate' in vars(self.__class__) and '_setstate' in vars(self.__class__)
def _getstate(self): def _getstate(self):
""" return [self._observer_callables_]
Returns the state of this class in a memento pattern.
The state must be a list-like structure of all the fields
this class needs to run.
See python doc "pickling" (`__getstate__` and `__setstate__`) for details.
"""
raise NotImplementedError, "To be able to use pickling you need to implement this method"
def _setstate(self, state): def _setstate(self, state):
""" self._observer_callables_ = state.pop()
Set the state (memento pattern) of this class to the given state.
Usually this is just the counterpart to _getstate, such that
an object is a copy of another when calling
copy = <classname>.__new__(*args,**kw)._setstate(<to_be_copied>._getstate())
See python doc "pickling" (`__getstate__` and `__setstate__`) for details.
"""
raise NotImplementedError, "To be able to use pickling you need to implement this method"
#=============================================================================== #===============================================================================
# Foundation framework for parameterized and param objects: # Foundation framework for parameterized and param objects:
#=============================================================================== #===============================================================================
class Parentable(object): class Parentable(Observable):
""" """
Enable an Object to have a parent. Enable an Object to have a parent.
@ -160,7 +172,7 @@ class Parentable(object):
_parent_ = None _parent_ = None
_parent_index_ = None _parent_index_ = None
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(Parentable, self).__init__() super(Parentable, self).__init__(*args, **kwargs)
def has_parent(self): def has_parent(self):
""" """
@ -284,13 +296,6 @@ class Indexable(object):
""" """
raise NotImplementedError, "Need to be able to get the raveled Index" raise NotImplementedError, "Need to be able to get the raveled Index"
def _internal_offset(self):
"""
The offset for this parameter inside its parent.
This has to account for shaped parameters!
"""
return 0
def _offset_for(self, param): def _offset_for(self, param):
""" """
Return the offset of the param inside this parameterized object. Return the offset of the param inside this parameterized object.
@ -308,7 +313,7 @@ class Indexable(object):
raise NotImplementedError, "shouldnt happen, raveld index transformation required from non parameterization object?" raise NotImplementedError, "shouldnt happen, raveld index transformation required from non parameterization object?"
class Constrainable(Nameable, Indexable, Observable): class Constrainable(Nameable, Indexable):
""" """
Make an object constrainable with Priors and Transformations. Make an object constrainable with Priors and Transformations.
TODO: Mappings!! TODO: Mappings!!
@ -367,21 +372,26 @@ class Constrainable(Nameable, Indexable, Observable):
self._highest_parent_._set_unfixed(unconstrained) self._highest_parent_._set_unfixed(unconstrained)
unfix = unconstrain_fixed unfix = unconstrain_fixed
def _ensure_fixes(self):
# Ensure that the fixes array is set:
# Parameterized: ones(self.size)
# Param: ones(self._realsize_
self._fixes_ = np.ones(self.size, dtype=bool)
def _set_fixed(self, index): def _set_fixed(self, index):
if not self._has_fixes(): self._fixes_ = np.ones(self.size, dtype=bool) self._ensure_fixes()
self._fixes_[index] = FIXED self._fixes_[index] = FIXED
if np.all(self._fixes_): self._fixes_ = None # ==UNFIXED if np.all(self._fixes_): self._fixes_ = None # ==UNFIXED
def _set_unfixed(self, index): def _set_unfixed(self, index):
if not self._has_fixes(): self._fixes_ = np.ones(self.size, dtype=bool) self._ensure_fixes()
# rav_i = self._raveled_index_for(param)[index]
self._fixes_[index] = UNFIXED self._fixes_[index] = UNFIXED
if np.all(self._fixes_): self._fixes_ = None # ==UNFIXED if np.all(self._fixes_): self._fixes_ = None # ==UNFIXED
def _connect_fixes(self): def _connect_fixes(self):
fixed_indices = self.constraints[__fixed__] fixed_indices = self.constraints[__fixed__]
if fixed_indices.size > 0: if fixed_indices.size > 0:
self._fixes_ = np.ones(self.size, dtype=bool) * UNFIXED self._ensure_fixes()
self._fixes_[fixed_indices] = FIXED self._fixes_[fixed_indices] = FIXED
else: else:
self._fixes_ = None self._fixes_ = None

View file

@ -9,7 +9,9 @@ from kern import CombinationKernel
class Add(CombinationKernel): class Add(CombinationKernel):
""" """
Add given list of kernels together. Add given list of kernels together.
propagates gradients thorugh. propagates gradients through.
This kernel will take over the active dims of it's subkernels passed in.
""" """
def __init__(self, subkerns, name='add'): def __init__(self, subkerns, name='add'):
super(Add, self).__init__(subkerns, name) super(Add, self).__init__(subkerns, name)

View file

@ -17,9 +17,9 @@ class Brownian(Kern):
:param variance: :param variance:
:type variance: float :type variance: float
""" """
def __init__(self, input_dim=1, variance=1., name='Brownian'): def __init__(self, input_dim=1, variance=1., active_dims=None, name='Brownian'):
assert input_dim==1, "Brownian motion in 1D only" assert input_dim==1, "Brownian motion in 1D only"
super(Brownian, self).__init__(input_dim, name) super(Brownian, self).__init__(input_dim, active_dims, name)
self.variance = Param('variance', variance, Logexp()) self.variance = Param('variance', variance, Logexp())
self.add_parameters(self.variance) self.add_parameters(self.variance)

View file

@ -34,8 +34,8 @@ class Coregionalize(Kern):
.. note: see coregionalization examples in GPy.examples.regression for some usage. .. note: see coregionalization examples in GPy.examples.regression for some usage.
""" """
def __init__(self, input_dim, output_dim, rank=1, W=None, kappa=None, name='coregion'): def __init__(self, input_dim, output_dim, rank=1, W=None, kappa=None, active_dims=None, name='coregion'):
super(Coregionalize, self).__init__(input_dim, name=name) super(Coregionalize, self).__init__(input_dim, active_dims, name=name)
self.output_dim = output_dim self.output_dim = output_dim
self.rank = rank self.rank = rank
if self.rank>output_dim: if self.rank>output_dim:

View file

@ -2,7 +2,7 @@
# Licensed under the BSD 3-clause license (see LICENSE.txt) # Licensed under the BSD 3-clause license (see LICENSE.txt)
from kern import Kern from kern import Kern, CombinationKernel
import numpy as np import numpy as np
import itertools import itertools
@ -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:]))] [ret[ind_i].append(slice(*indexes_i)) for ind_i,indexes_i in zip(ind[switchpoints[:-1]],zip(switchpoints,switchpoints[1:]))]
return ret return ret
class IndependentOutputs(Kern): class IndependentOutputs(CombinationKernel):
""" """
A kernel which can represent several independent functions. A kernel which can represent several independent functions.
this kernel 'switches off' parts of the matrix where the output indexes are different. this kernel 'switches off' parts of the matrix where the output indexes are different.
@ -41,12 +41,12 @@ class IndependentOutputs(Kern):
the rest of the columns of X are passed to the underlying kernel for computation (in blocks). the rest of the columns of X are passed to the underlying kernel for computation (in blocks).
""" """
def __init__(self, index_dim, kern, name='independ'): def __init__(self, kern, index_dim=-1, name='independ'):
assert isinstance(index_dim, int), "IndependentOutputs kernel is only defined with one input dimension being the indeces" assert isinstance(index_dim, int), "IndependentOutputs kernel is only defined with one input dimension being the indeces"
super(IndependentOutputs, self).__init__(np.r_[0:max(max(kern.active_dims)+1, index_dim+1)], name) super(IndependentOutputs, self).__init__(kernels=[kern], extra_dims=[index_dim], name=name)
self.index_dim = index_dim self.index_dim = index_dim
self.kern = kern self.kern = kern
self.add_parameters(self.kern) #self.add_parameters(self.kern)
def K(self,X ,X2=None): def K(self,X ,X2=None):
slices = index_to_slices(X[:,self.index_dim]) slices = index_to_slices(X[:,self.index_dim])

View file

@ -16,26 +16,32 @@ class Kern(Parameterized):
__metaclass__ = KernCallsViaSlicerMeta __metaclass__ = KernCallsViaSlicerMeta
#=========================================================================== #===========================================================================
_debug=False _debug=False
def __init__(self, input_dim, name, *a, **kw): def __init__(self, input_dim, active_dims, name, *a, **kw):
""" """
The base class for a kernel: a positive definite function The base class for a kernel: a positive definite function
which forms of a covariance function (kernel). which forms of a covariance function (kernel).
:param input_dim: the number of input dimensions to the function :param int input_dim: the number of input dimensions to the function
:type input_dim: int :param array-like|slice active_dims: list of indices on which dimensions this kernel works on
Do not instantiate. Do not instantiate.
""" """
super(Kern, self).__init__(name=name, *a, **kw) super(Kern, self).__init__(name=name, *a, **kw)
if isinstance(input_dim, int): self.active_dims = active_dims if active_dims is not None else slice(0, input_dim)
self.active_dims = np.r_[0:input_dim] self.input_dim = input_dim
self.input_dim = input_dim assert isinstance(self.active_dims, (slice, list, tuple, np.ndarray)), 'active_dims needs to be an array-like or slice object over dimensions, {} given'.format(self.active_dims.__class__)
if isinstance(self.active_dims, slice):
self.active_dims = slice(self.active_dims.start or 0, self.active_dims.stop or self.input_dim, self.active_dims.step or 1)
active_dim_size = int(np.round((self.active_dims.stop-self.active_dims.start)/self.active_dims.step))
elif isinstance(self.active_dims, np.ndarray):
assert self.active_dims.ndim == 1, 'only flat indices allowed, given active_dims.shape={}, provide only indexes to the dimensions of the input'.format(self.active_dims.shape)
active_dim_size = self.active_dims.size
else: else:
self.active_dims = np.r_[input_dim] active_dim_size = len(self.active_dims)
self.input_dim = len(self.active_dims) assert active_dim_size == self.input_dim, "input_dim={} does not match len(active_dim)={}, active_dims={}".format(self.input_dim, active_dim_size, self.active_dims)
self._sliced_X = 0 self._sliced_X = 0
@Cache_this(limit=10)#, ignore_args = (0,)) @Cache_this(limit=10)
def _slice_X(self, X): def _slice_X(self, X):
return X[:, self.active_dims] return X[:, self.active_dims]
@ -69,9 +75,7 @@ class Kern(Parameterized):
def update_gradients_full(self, dL_dK, X, X2): def update_gradients_full(self, dL_dK, X, X2):
"""Set the gradients of all parameters when doing full (N) inference.""" """Set the gradients of all parameters when doing full (N) inference."""
raise NotImplementedError raise NotImplementedError
def update_gradients_diag(self, dL_dKdiag, X):
"""Set the gradients for all parameters for the derivative of the diagonal of the covariance w.r.t the kernel parameters."""
raise NotImplementedError
def update_gradients_expectations(self, dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior): def update_gradients_expectations(self, dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior):
""" """
Set the gradients of all parameters when doing inference with Set the gradients of all parameters when doing inference with
@ -193,13 +197,28 @@ class Kern(Parameterized):
super(Kern, self)._setstate(state) super(Kern, self)._setstate(state)
class CombinationKernel(Kern): class CombinationKernel(Kern):
def __init__(self, kernels, name): """
Abstract super class for combination kernels.
A combination kernel combines (a list of) kernels and works on those.
Examples are the HierarchicalKernel or Add and Prod kernels.
"""
def __init__(self, kernels, name, extra_dims=[]):
"""
Abstract super class for combination kernels.
A combination kernel combines (a list of) kernels and works on those.
Examples are the HierarchicalKernel or Add and Prod kernels.
:param list kernels: List of kernels to combine (can be only one element)
:param str name: name of the combination kernel
:param array-like|slice extra_dims: if needed extra dimensions for the combination kernel to work on
"""
assert all([isinstance(k, Kern) for k in kernels]) assert all([isinstance(k, Kern) for k in kernels])
# make sure the active dimensions of all underlying kernels are covered: active_dims = reduce(np.union1d, (np.r_[x.active_dims] for x in kernels), np.array([], dtype=int))
ma = reduce(lambda a,b: max(a, max(b)), (x.active_dims for x in kernels), 0) input_dim = active_dims.max()+1 + len(extra_dims)
input_dim = np.r_[0:ma+1] active_dims = slice(active_dims.max()+1+len(extra_dims))
# initialize the kernel with the full input_dim # initialize the kernel with the full input_dim
super(CombinationKernel, self).__init__(input_dim, name) super(CombinationKernel, self).__init__(input_dim, active_dims, name)
self.extra_dims = extra_dims
self.add_parameters(*kernels) self.add_parameters(*kernels)
@property @property

View file

@ -34,8 +34,8 @@ class Linear(Kern):
""" """
def __init__(self, input_dim, variances=None, ARD=False, name='linear'): def __init__(self, input_dim, variances=None, ARD=False, active_dims=None, name='linear'):
super(Linear, self).__init__(input_dim, name) super(Linear, self).__init__(input_dim, active_dims, name)
self.ARD = ARD self.ARD = ARD
if not ARD: if not ARD:
if variances is not None: if variances is not None:

View file

@ -31,8 +31,8 @@ class MLP(Kern):
""" """
def __init__(self, input_dim, variance=1., weight_variance=1., bias_variance=100., name='mlp'): def __init__(self, input_dim, variance=1., weight_variance=1., bias_variance=100., active_dims=None, name='mlp'):
super(MLP, self).__init__(input_dim, name) super(MLP, self).__init__(input_dim, active_dims, name)
self.variance = Param('variance', variance, Logexp()) self.variance = Param('variance', variance, Logexp())
self.weight_variance = Param('weight_variance', weight_variance, Logexp()) self.weight_variance = Param('weight_variance', weight_variance, Logexp())
self.bias_variance = Param('bias_variance', bias_variance, Logexp()) self.bias_variance = Param('bias_variance', bias_variance, Logexp())

View file

@ -10,7 +10,7 @@ from ...core.parameterization.param import Param
from ...core.parameterization.transformations import Logexp from ...core.parameterization.transformations import Logexp
class Periodic(Kern): class Periodic(Kern):
def __init__(self, input_dim, variance, lengthscale, period, n_freq, lower, upper, name): def __init__(self, input_dim, variance, lengthscale, period, n_freq, lower, upper, active_dims, name):
""" """
:type input_dim: int :type input_dim: int
:param variance: the variance of the Matern kernel :param variance: the variance of the Matern kernel
@ -25,7 +25,7 @@ class Periodic(Kern):
""" """
assert input_dim==1, "Periodic kernels are only defined for input_dim=1" assert input_dim==1, "Periodic kernels are only defined for input_dim=1"
super(Periodic, self).__init__(input_dim, name) super(Periodic, self).__init__(input_dim, active_dims, name)
self.input_dim = input_dim self.input_dim = input_dim
self.lower,self.upper = lower, upper self.lower,self.upper = lower, upper
self.n_freq = n_freq self.n_freq = n_freq
@ -77,8 +77,8 @@ class PeriodicExponential(Periodic):
Only defined for input_dim=1. Only defined for input_dim=1.
""" """
def __init__(self, input_dim=1, variance=1., lengthscale=1., period=2.*np.pi, n_freq=10, lower=0., upper=4*np.pi, name='periodic_exponential'): def __init__(self, input_dim=1, variance=1., lengthscale=1., period=2.*np.pi, n_freq=10, lower=0., upper=4*np.pi, active_dims=None, name='periodic_exponential'):
super(PeriodicExponential, self).__init__(input_dim, variance, lengthscale, period, n_freq, lower, upper, name) super(PeriodicExponential, self).__init__(input_dim, variance, lengthscale, period, n_freq, lower, upper, active_dims, name)
def parameters_changed(self): def parameters_changed(self):
self.a = [1./self.lengthscale, 1.] self.a = [1./self.lengthscale, 1.]
@ -187,8 +187,8 @@ class PeriodicMatern32(Periodic):
""" """
def __init__(self, input_dim=1, variance=1., lengthscale=1., period=2.*np.pi, n_freq=10, lower=0., upper=4*np.pi, name='periodic_Matern32'): def __init__(self, input_dim=1, variance=1., lengthscale=1., period=2.*np.pi, n_freq=10, lower=0., upper=4*np.pi, active_dims=None, name='periodic_Matern32'):
super(PeriodicMatern32, self).__init__(input_dim, variance, lengthscale, period, n_freq, lower, upper, name) super(PeriodicMatern32, self).__init__(input_dim, variance, lengthscale, period, n_freq, lower, upper, active_dims, name)
def parameters_changed(self): def parameters_changed(self):
self.a = [3./self.lengthscale**2, 2*np.sqrt(3)/self.lengthscale, 1.] self.a = [3./self.lengthscale**2, 2*np.sqrt(3)/self.lengthscale, 1.]
self.b = [1,self.lengthscale**2/3] self.b = [1,self.lengthscale**2/3]
@ -300,8 +300,8 @@ class PeriodicMatern52(Periodic):
""" """
def __init__(self, input_dim=1, variance=1., lengthscale=1., period=2.*np.pi, n_freq=10, lower=0., upper=4*np.pi, name='periodic_Matern52'): def __init__(self, input_dim=1, variance=1., lengthscale=1., period=2.*np.pi, n_freq=10, lower=0., upper=4*np.pi, active_dims=None, name='periodic_Matern52'):
super(PeriodicMatern52, self).__init__(input_dim, variance, lengthscale, period, n_freq, lower, upper, name) super(PeriodicMatern52, self).__init__(input_dim, variance, lengthscale, period, n_freq, lower, upper, active_dims, name)
def parameters_changed(self): def parameters_changed(self):
self.a = [5*np.sqrt(5)/self.lengthscale**3, 15./self.lengthscale**2,3*np.sqrt(5)/self.lengthscale, 1.] self.a = [5*np.sqrt(5)/self.lengthscale**3, 15./self.lengthscale**2,3*np.sqrt(5)/self.lengthscale, 1.]

View file

@ -19,8 +19,8 @@ class RBF(Stationary):
k(r) = \sigma^2 \exp \\bigg(- \\frac{1}{2} r^2 \\bigg) k(r) = \sigma^2 \exp \\bigg(- \\frac{1}{2} r^2 \\bigg)
""" """
def __init__(self, input_dim, variance=1., lengthscale=None, ARD=False, name='rbf'): def __init__(self, input_dim, variance=1., lengthscale=None, ARD=False, active_dims=None, name='rbf'):
super(RBF, self).__init__(input_dim, variance, lengthscale, ARD, name) super(RBF, self).__init__(input_dim, variance, lengthscale, ARD, active_dims, name)
self.weave_options = {} self.weave_options = {}
def K_of_r(self, r): def K_of_r(self, r):

View file

@ -33,9 +33,9 @@ class SSRBF(Stationary):
.. Note: this object implements both the ARD and 'spherical' version of the function .. Note: this object implements both the ARD and 'spherical' version of the function
""" """
def __init__(self, input_dim, variance=1., lengthscale=None, ARD=True, name='SSRBF'): def __init__(self, input_dim, variance=1., lengthscale=None, ARD=True, active_dims=None, name='SSRBF'):
assert ARD==True, "Not Implemented!" assert ARD==True, "Not Implemented!"
super(SSRBF, self).__init__(input_dim, variance, lengthscale, ARD, name) super(SSRBF, self).__init__(input_dim, variance, lengthscale, ARD, active_dims, name)
def K_of_r(self, r): def K_of_r(self, r):
return self.variance * np.exp(-0.5 * r**2) return self.variance * np.exp(-0.5 * r**2)

View file

@ -9,8 +9,8 @@ from ...core.parameterization.transformations import Logexp
import numpy as np import numpy as np
class Static(Kern): class Static(Kern):
def __init__(self, input_dim, variance, name): def __init__(self, input_dim, variance, active_dims, name):
super(Static, self).__init__(input_dim, name) super(Static, self).__init__(input_dim, active_dims, name)
self.variance = Param('variance', variance, Logexp()) self.variance = Param('variance', variance, Logexp())
self.add_parameters(self.variance) self.add_parameters(self.variance)
@ -43,8 +43,8 @@ class Static(Kern):
class White(Static): class White(Static):
def __init__(self, input_dim, variance=1., name='white'): def __init__(self, input_dim, variance=1., active_dims=None, name='white'):
super(White, self).__init__(input_dim, variance, name) super(White, self).__init__(input_dim, variance, active_dims, name)
def K(self, X, X2=None): def K(self, X, X2=None):
if X2 is None: if X2 is None:
@ -66,8 +66,8 @@ class White(Static):
class Bias(Static): class Bias(Static):
def __init__(self, input_dim, variance=1., name='bias'): def __init__(self, input_dim, variance=1., active_dims=None, name='bias'):
super(Bias, self).__init__(input_dim, variance, name) super(Bias, self).__init__(input_dim, variance, active_dims, name)
def K(self, X, X2=None): def K(self, X, X2=None):
shape = (X.shape[0], X.shape[0] if X2 is None else X2.shape[0]) shape = (X.shape[0], X.shape[0] if X2 is None else X2.shape[0])
@ -90,14 +90,14 @@ class Bias(Static):
self.variance.gradient = dL_dpsi0.sum() + dL_dpsi1.sum() + 2.*self.variance*dL_dpsi2.sum() self.variance.gradient = dL_dpsi0.sum() + dL_dpsi1.sum() + 2.*self.variance*dL_dpsi2.sum()
class Fixed(Static): class Fixed(Static):
def __init__(self, input_dim, covariance_matrix, variance=1., name='fixed'): def __init__(self, input_dim, covariance_matrix, variance=1., active_dims=None, name='fixed'):
""" """
:param input_dim: the number of input dimensions :param input_dim: the number of input dimensions
:type input_dim: int :type input_dim: int
:param variance: the variance of the kernel :param variance: the variance of the kernel
:type variance: float :type variance: float
""" """
super(Bias, self).__init__(input_dim, variance, name) super(Bias, self).__init__(input_dim, variance, active_dims, name)
self.fixed_K = covariance_matrix self.fixed_K = covariance_matrix
def K(self, X, X2): def K(self, X, X2):
return self.variance * self.fixed_K return self.variance * self.fixed_K

View file

@ -41,8 +41,8 @@ class Stationary(Kern):
""" """
def __init__(self, input_dim, variance, lengthscale, ARD, name): def __init__(self, input_dim, variance, lengthscale, ARD, active_dims, name):
super(Stationary, self).__init__(input_dim, name) super(Stationary, self).__init__(input_dim, active_dims, name)
self.ARD = ARD self.ARD = ARD
if not ARD: if not ARD:
if lengthscale is None: if lengthscale is None:
@ -186,8 +186,8 @@ class Stationary(Kern):
return np.ones(self.input_dim)/self.lengthscale return np.ones(self.input_dim)/self.lengthscale
class Exponential(Stationary): class Exponential(Stationary):
def __init__(self, input_dim, variance=1., lengthscale=None, ARD=False, name='Exponential'): def __init__(self, input_dim, variance=1., lengthscale=None, ARD=False, active_dims=None, name='Exponential'):
super(Exponential, self).__init__(input_dim, variance, lengthscale, ARD, name) super(Exponential, self).__init__(input_dim, variance, lengthscale, ARD, active_dims, name)
def K_of_r(self, r): def K_of_r(self, r):
return self.variance * np.exp(-0.5 * r) return self.variance * np.exp(-0.5 * r)
@ -205,8 +205,8 @@ class Matern32(Stationary):
""" """
def __init__(self, input_dim, variance=1., lengthscale=None, ARD=False, name='Mat32'): def __init__(self, input_dim, variance=1., lengthscale=None, ARD=False, active_dims=None, name='Mat32'):
super(Matern32, self).__init__(input_dim, variance, lengthscale, ARD, name) super(Matern32, self).__init__(input_dim, variance, lengthscale, ARD, active_dims, name)
def K_of_r(self, r): def K_of_r(self, r):
return self.variance * (1. + np.sqrt(3.) * r) * np.exp(-np.sqrt(3.) * r) return self.variance * (1. + np.sqrt(3.) * r) * np.exp(-np.sqrt(3.) * r)
@ -249,8 +249,8 @@ class Matern52(Stationary):
k(r) = \sigma^2 (1 + \sqrt{5} r + \\frac53 r^2) \exp(- \sqrt{5} r) k(r) = \sigma^2 (1 + \sqrt{5} r + \\frac53 r^2) \exp(- \sqrt{5} r)
""" """
def __init__(self, input_dim, variance=1., lengthscale=None, ARD=False, name='Mat52'): def __init__(self, input_dim, variance=1., lengthscale=None, ARD=False, active_dims=None, name='Mat52'):
super(Matern52, self).__init__(input_dim, variance, lengthscale, ARD, name) super(Matern52, self).__init__(input_dim, variance, lengthscale, ARD, active_dims, name)
def K_of_r(self, r): def K_of_r(self, r):
return self.variance*(1+np.sqrt(5.)*r+5./3*r**2)*np.exp(-np.sqrt(5.)*r) return self.variance*(1+np.sqrt(5.)*r+5./3*r**2)*np.exp(-np.sqrt(5.)*r)
@ -291,8 +291,8 @@ class Matern52(Stationary):
class ExpQuad(Stationary): class ExpQuad(Stationary):
def __init__(self, input_dim, variance=1., lengthscale=None, ARD=False, name='ExpQuad'): def __init__(self, input_dim, variance=1., lengthscale=None, ARD=False, active_dims=None, name='ExpQuad'):
super(ExpQuad, self).__init__(input_dim, variance, lengthscale, ARD, name) super(ExpQuad, self).__init__(input_dim, variance, lengthscale, ARD, active_dims, name)
def K_of_r(self, r): def K_of_r(self, r):
return self.variance * np.exp(-0.5 * r**2) return self.variance * np.exp(-0.5 * r**2)
@ -301,8 +301,8 @@ class ExpQuad(Stationary):
return -r*self.K_of_r(r) return -r*self.K_of_r(r)
class Cosine(Stationary): class Cosine(Stationary):
def __init__(self, input_dim, variance=1., lengthscale=None, ARD=False, name='Cosine'): def __init__(self, input_dim, variance=1., lengthscale=None, ARD=False, active_dims=None, name='Cosine'):
super(Cosine, self).__init__(input_dim, variance, lengthscale, ARD, name) super(Cosine, self).__init__(input_dim, variance, lengthscale, ARD, active_dims, name)
def K_of_r(self, r): def K_of_r(self, r):
return self.variance * np.cos(r) return self.variance * np.cos(r)
@ -322,8 +322,8 @@ class RatQuad(Stationary):
""" """
def __init__(self, input_dim, variance=1., lengthscale=None, power=2., ARD=False, name='ExpQuad'): def __init__(self, input_dim, variance=1., lengthscale=None, power=2., ARD=False, active_dims=None, name='ExpQuad'):
super(RatQuad, self).__init__(input_dim, variance, lengthscale, ARD, name) super(RatQuad, self).__init__(input_dim, variance, lengthscale, ARD, active_dims, name)
self.power = Param('power', power, Logexp()) self.power = Param('power', power, Logexp())
self.add_parameters(self.power) self.add_parameters(self.power)

View file

@ -26,13 +26,13 @@ class Sympykern(Kern):
- to handle multiple inputs, call them x_1, z_1, etc - to handle multiple inputs, call them x_1, z_1, etc
- to handle multpile correlated outputs, you'll need to add parameters with an index, such as lengthscale_i and lengthscale_j. - to handle multpile correlated outputs, you'll need to add parameters with an index, such as lengthscale_i and lengthscale_j.
""" """
def __init__(self, input_dim, k=None, output_dim=1, name=None, param=None): def __init__(self, input_dim, k=None, output_dim=1, name=None, param=None, active_dims=None):
if name is None: if name is None:
name='sympykern' name='sympykern'
if k is None: if k is None:
raise ValueError, "You must provide an argument for the covariance function." raise ValueError, "You must provide an argument for the covariance function."
super(Sympykern, self).__init__(input_dim, name) super(Sympykern, self).__init__(input_dim, active_dims, name)
self._sp_k = k self._sp_k = k

View file

@ -17,24 +17,33 @@ class Test(unittest.TestCase):
self.param_index.add(one, [3]) self.param_index.add(one, [3])
self.param_index.add(two, [0,5]) self.param_index.add(two, [0,5])
self.param_index.add(three, [2,4,7]) self.param_index.add(three, [2,4,7])
self.view = ParameterIndexOperationsView(self.param_index, 2, 6)
def test_clear(self):
self.param_index.clear()
self.assertDictEqual(self.param_index._properties, {})
def test_remove(self): def test_remove(self):
self.param_index.remove(three, np.r_[3:10]) self.param_index.remove(three, np.r_[3:10])
self.assertListEqual(self.param_index[three].tolist(), [2]) self.assertListEqual(self.param_index[three].tolist(), [2])
self.param_index.remove(one, [1]) self.param_index.remove(one, [1])
self.assertListEqual(self.param_index[one].tolist(), [3]) self.assertListEqual(self.param_index[one].tolist(), [3])
self.assertListEqual(self.param_index.remove('not in there', []).tolist(), [])
self.param_index.remove(one, [9])
self.assertListEqual(self.param_index[one].tolist(), [3])
self.assertListEqual(self.param_index.remove('not in there', [2,3,4]).tolist(), [])
def test_shift_left(self): def test_shift_left(self):
self.param_index.shift_left(1, 2) self.view.shift_left(0, 2)
self.assertListEqual(self.param_index[three].tolist(), [2,5]) self.assertListEqual(self.param_index[three].tolist(), [2,5])
self.assertListEqual(self.param_index[two].tolist(), [0,3]) self.assertListEqual(self.param_index[two].tolist(), [0,3])
self.assertListEqual(self.param_index[one].tolist(), [1]) self.assertListEqual(self.param_index[one].tolist(), [])
def test_shift_right(self): def test_shift_right(self):
self.param_index.shift_right(5, 2) self.view.shift_right(3, 2)
self.assertListEqual(self.param_index[three].tolist(), [2,4,9]) self.assertListEqual(self.param_index[three].tolist(), [2,4,9])
self.assertListEqual(self.param_index[two].tolist(), [0,7]) self.assertListEqual(self.param_index[two].tolist(), [0,7])
self.assertListEqual(self.param_index[one].tolist(), [3]) self.assertListEqual(self.param_index[one].tolist(), [3])
def test_index_view(self): def test_index_view(self):
#======================================================================= #=======================================================================
@ -44,17 +53,17 @@ class Test(unittest.TestCase):
# three three three # three three three
# view: [0 1 2 3 4 5 ] # view: [0 1 2 3 4 5 ]
#======================================================================= #=======================================================================
view = ParameterIndexOperationsView(self.param_index, 2, 6) self.view = ParameterIndexOperationsView(self.param_index, 2, 6)
self.assertSetEqual(set(view.properties()), set([one, two, three])) self.assertSetEqual(set(self.view.properties()), set([one, two, three]))
for v,p in zip(view.properties_for(np.r_[:6]), self.param_index.properties_for(np.r_[2:2+6])): for v,p in zip(self.view.properties_for(np.r_[:6]), self.param_index.properties_for(np.r_[2:2+6])):
self.assertEqual(v, p) self.assertEqual(v, p)
self.assertSetEqual(set(view[two]), set([3])) self.assertSetEqual(set(self.view[two]), set([3]))
self.assertSetEqual(set(self.param_index[two]), set([0, 5])) self.assertSetEqual(set(self.param_index[two]), set([0, 5]))
view.add(two, np.array([0])) self.view.add(two, np.array([0]))
self.assertSetEqual(set(view[two]), set([0,3])) self.assertSetEqual(set(self.view[two]), set([0,3]))
self.assertSetEqual(set(self.param_index[two]), set([0, 2, 5])) self.assertSetEqual(set(self.param_index[two]), set([0, 2, 5]))
view.clear() self.view.clear()
for v,p in zip(view.properties_for(np.r_[:6]), self.param_index.properties_for(np.r_[2:2+6])): for v,p in zip(self.view.properties_for(np.r_[:6]), self.param_index.properties_for(np.r_[2:2+6])):
self.assertEqual(v, p) self.assertEqual(v, p)
self.assertEqual(v, []) self.assertEqual(v, [])
param_index = ParameterIndexOperations() param_index = ParameterIndexOperations()
@ -62,11 +71,17 @@ class Test(unittest.TestCase):
param_index.add(two, [0,5]) param_index.add(two, [0,5])
param_index.add(three, [2,4,7]) param_index.add(three, [2,4,7])
view2 = ParameterIndexOperationsView(param_index, 2, 6) view2 = ParameterIndexOperationsView(param_index, 2, 6)
view.update(view2) self.view.update(view2)
for [i,v],[i2,v2] in zip(sorted(param_index.items()), sorted(self.param_index.items())): for [i,v],[i2,v2] in zip(sorted(param_index.items()), sorted(self.param_index.items())):
self.assertEqual(i, i2) self.assertEqual(i, i2)
self.assertTrue(np.all(v == v2)) self.assertTrue(np.all(v == v2))
def test_misc(self):
for k,v in self.param_index.copy()._properties.iteritems():
self.assertListEqual(self.param_index[k].tolist(), v.tolist())
self.assertEqual(self.param_index.size, 6)
self.assertEqual(self.view.size, 5)
if __name__ == "__main__": if __name__ == "__main__":
#import sys;sys.argv = ['', 'Test.test_index_view'] #import sys;sys.argv = ['', 'Test.test_index_view']
unittest.main() unittest.main()

View file

@ -228,12 +228,12 @@ class KernelGradientTestsContinuous(unittest.TestCase):
self.assertTrue(check_kernel_gradient_functions(k, X=self.X, X2=self.X2, verbose=verbose)) self.assertTrue(check_kernel_gradient_functions(k, X=self.X, X2=self.X2, verbose=verbose))
def test_Prod(self): def test_Prod(self):
k = GPy.kern.Matern32([2,3]) * GPy.kern.RBF([0,4]) + GPy.kern.Linear(self.D) k = GPy.kern.Matern32(2, active_dims=[2,3]) * GPy.kern.RBF(2, active_dims=[0,4]) + GPy.kern.Linear(self.D)
k.randomize() k.randomize()
self.assertTrue(check_kernel_gradient_functions(k, X=self.X, X2=self.X2, verbose=verbose)) self.assertTrue(check_kernel_gradient_functions(k, X=self.X, X2=self.X2, verbose=verbose))
def test_Add(self): def test_Add(self):
k = GPy.kern.Matern32([2,3]) + GPy.kern.RBF([0,4]) + GPy.kern.Linear(self.D) k = GPy.kern.Matern32(2, active_dims=[2,3]) + GPy.kern.RBF(2, active_dims=[0,4]) + GPy.kern.Linear(self.D)
k.randomize() k.randomize()
self.assertTrue(check_kernel_gradient_functions(k, X=self.X, X2=self.X2, verbose=verbose)) self.assertTrue(check_kernel_gradient_functions(k, X=self.X, X2=self.X2, verbose=verbose))
@ -282,15 +282,16 @@ class KernelTestsMiscellaneous(unittest.TestCase):
def setUp(self): def setUp(self):
N, D = 100, 10 N, D = 100, 10
self.X = np.linspace(-np.pi, +np.pi, N)[:,None] * np.ones(D) self.X = np.linspace(-np.pi, +np.pi, N)[:,None] * np.ones(D)
self.rbf = GPy.kern.RBF(range(2)) self.rbf = GPy.kern.RBF(2, active_dims=slice(0,4,2))
self.linear = GPy.kern.Linear((3,6)) self.linear = GPy.kern.Linear(2, active_dims=(3,9))
self.matern = GPy.kern.Matern32(np.array([2,4,7])) self.matern = GPy.kern.Matern32(3, active_dims=np.array([2,4,9]))
self.sumkern = self.rbf + self.linear self.sumkern = self.rbf + self.linear
self.sumkern += self.matern self.sumkern += self.matern
self.sumkern.randomize() self.sumkern.randomize()
def test_active_dims(self): def test_active_dims(self):
self.assertListEqual(self.sumkern.active_dims.tolist(), range(8)) self.assertEqual(self.sumkern.input_dim, 10)
self.assertEqual(self.sumkern.active_dims, slice(0, 10, 1))
def test_which_parts(self): 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))) 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)))
@ -310,11 +311,12 @@ class KernelTestsNonContinuous(unittest.TestCase):
self.X_block[N:N+N1, D:D+D] = self.X2 self.X_block[N:N+N1, D:D+D] = self.X2
self.X_block[0:N, -1] = 1 self.X_block[0:N, -1] = 1
self.X_block[N:N+1, -1] = 2 self.X_block[N:N+1, -1] = 2
self.X_block = self.X_block[self.X_block.argsort(0)[:, -1], :]
def test_IndependantOutputs(self):
def test_IndependentOutputs(self):
k = GPy.kern.RBF(self.D) k = GPy.kern.RBF(self.D)
kern = GPy.kern.IndependentOutputs(self.D+self.D,k) kern = GPy.kern.IndependentOutputs(k, -1)
self.assertTrue(check_kernel_gradient_functions(kern, X=self.X, X2=self.X2, verbose=verbose)) self.assertTrue(check_kernel_gradient_functions(kern, X=self.X_block, X2=self.X_block, verbose=verbose))
if __name__ == "__main__": if __name__ == "__main__":
print "Running unit tests, please be (very) patient..." print "Running unit tests, please be (very) patient..."

View file

@ -7,8 +7,24 @@ import unittest
import GPy import GPy
import numpy as np import numpy as np
from GPy.core.parameterization.parameter_core import HierarchyError from GPy.core.parameterization.parameter_core import HierarchyError
from GPy.core.parameterization.array_core import ObservableArray
class Test(unittest.TestCase): class ArrayCoreTest(unittest.TestCase):
def setUp(self):
self.X = np.random.normal(1,1, size=(100,10))
self.obsX = ObservableArray(self.X)
def test_init(self):
X = ObservableArray(self.X)
X2 = ObservableArray(X)
self.assertIs(X, X2, "no new Observable array, when Observable is given")
def test_slice(self):
t1 = self.X[2:78]
t2 = self.obsX[2:78]
self.assertListEqual(t1.tolist(), t2.tolist(), "Slicing should be the exact same, as in ndarray")
class ParameterizedTest(unittest.TestCase):
def setUp(self): def setUp(self):
self.rbf = GPy.kern.RBF(1) self.rbf = GPy.kern.RBF(1)
@ -35,7 +51,6 @@ class Test(unittest.TestCase):
self.white.fix(warning=False) self.white.fix(warning=False)
self.test1.remove_parameter(self.test1.param) self.test1.remove_parameter(self.test1.param)
self.assertTrue(self.test1._has_fixes()) self.assertTrue(self.test1._has_fixes())
from GPy.core.parameterization.transformations import FIXED, UNFIXED from GPy.core.parameterization.transformations import FIXED, UNFIXED
self.assertListEqual(self.test1._fixes_.tolist(),[UNFIXED,UNFIXED,FIXED]) self.assertListEqual(self.test1._fixes_.tolist(),[UNFIXED,UNFIXED,FIXED])
@ -51,12 +66,12 @@ class Test(unittest.TestCase):
self.assertListEqual(self.white._fixes_.tolist(), [FIXED]) self.assertListEqual(self.white._fixes_.tolist(), [FIXED])
self.assertEquals(self.white.constraints._offset, 0) self.assertEquals(self.white.constraints._offset, 0)
self.assertIs(self.test1.constraints, self.rbf.constraints._param_index_ops) self.assertIs(self.test1.constraints, self.rbf.constraints._param_index_ops)
self.assertIs(self.test1.constraints, self.param.constraints._param_index_ops) self.assertIs(self.test1.constraints, self.param.constraints._param_index_ops)
self.test1.add_parameter(self.white, 0) self.test1.add_parameter(self.white, 0)
self.assertIs(self.test1.constraints, self.white.constraints._param_index_ops) self.assertIs(self.test1.constraints, self.white.constraints._param_index_ops)
self.assertIs(self.test1.constraints, self.rbf.constraints._param_index_ops) self.assertIs(self.test1.constraints, self.rbf.constraints._param_index_ops)
self.assertIs(self.test1.constraints, self.param.constraints._param_index_ops) self.assertIs(self.test1.constraints, self.param.constraints._param_index_ops)
self.assertListEqual(self.test1.constraints[__fixed__].tolist(), [0]) self.assertListEqual(self.test1.constraints[__fixed__].tolist(), [0])
self.assertIs(self.white._fixes_,None) self.assertIs(self.white._fixes_,None)
self.assertListEqual(self.test1._fixes_.tolist(),[FIXED] + [UNFIXED] * 52) self.assertListEqual(self.test1._fixes_.tolist(),[FIXED] + [UNFIXED] * 52)
@ -69,7 +84,7 @@ class Test(unittest.TestCase):
self.assertListEqual(self.test1.constraints[Logexp()].tolist(), [0,1]) self.assertListEqual(self.test1.constraints[Logexp()].tolist(), [0,1])
def test_add_parameter_already_in_hirarchy(self): def test_add_parameter_already_in_hirarchy(self):
self.assertRaises(HierarchyError, self.test1.add_parameter, self.white._parameters_[0]) self.assertRaises(HierarchyError, self.test1.add_parameter, self.white._parameters_[0])
def test_default_constraints(self): def test_default_constraints(self):
self.assertIs(self.rbf.variance.constraints._param_index_ops, self.rbf.constraints._param_index_ops) self.assertIs(self.rbf.variance.constraints._param_index_ops, self.rbf.constraints._param_index_ops)