#================================================================================
# Marion Neumann [marion dot neumann at uni-bonn dot de]
# Daniel Marthaler [dan dot marthaler at gmail dot com]
# Shan Huang [shan dot huang at iais dot fraunhofer dot de]
# Kristian Kersting [kristian dot kersting at cs dot tu-dortmund dot de]
#
# This file is part of pyGPs.
# The software package is released under the BSD 2-Clause (FreeBSD) License.
#
# Copyright (c) by
# Marion Neumann, Daniel Marthaler, Shan Huang & Kristian Kersting, 18/02/2014
#================================================================================
# mean functions to be use by Gaussian process functions. There are two
# different kinds of mean functions: simple and composite:
#
# simple mean functions:
#
# Zero - zero mean function
# One - one mean function
# Const - constant mean function
# Linear - linear mean function
#
# composite mean functions:
#
# ScaleOfMean - scaled version of a mean function
# PowerOfMean - power of a mean function
# ProductOfMean - products of mean functions
# SumOfMean - sums of mean functions
#
#
# This is a object-oriented python implementation of gpml functionality
# (Copyright (c) by Carl Edward Rasmussen and Hannes Nickisch, 2011-02-18).
# based on the functional-version of python implementation
# (Copyright (c) by Marion Neumann and Daniel Marthaler, 20/05/2013)
#
#
# Copyright (c) by Marion Neumann and Shan Huang, Sep.2013
import numpy as np
import math
[docs]class Mean(object):
'''
The base function for mean function
'''
def __init__(self):
super(Mean, self).__init__()
self.hyp = []
self.para = []
def __repr__(self):
strvalue =str(type(self))+': to get the mean vector or mean derviatives use: \n'+\
'model.meanfunc.getMean()\n'+\
'model.meanfunc.getDerMatrix()'
return strvalue
# overloading
def __add__(self,mean):
'''
Overloading + operator.
:param mean: mean function
:return: an instance of SumOfMean
'''
return SumOfMean(self,mean)
# overloading
def __mul__(self,other):
'''
Overloading * operator.
Using * for both multiplication with scalar and product of means
depending on the type of the two objects.
:param other: mean function as product or int/float as scalar
:return: an instance of ScaleOfMean or ProductOfMean
'''
if isinstance(other, int) or isinstance(other, float):
return ScaleOfMean(self,other)
elif isinstance(other, Mean):
return ProductOfMean(self,other)
else:
print "only numbers and Means are allowed for *"
# overloading
__rmul__ = __mul__
# overloading
def __pow__(self,number):
'''
Overloading ** operator.
:param int number: power of the mean function
:return: an instance of PowerOfMean
'''
if isinstance(number, int) and number > 0:
return PowerOfMean(self,number)
else:
print "only non-zero integers are supported for **"
[docs] def getMean(self, x=None):
'''
Get the mean vector based on the inputs.
:param x: training data
'''
pass
[docs] def getDerMatrix(self, x=None, der=None):
'''
Compute derivatives wrt. hyperparameters.
:param x: training inputs
:param int der: index of hyperparameter whose derivative to be computed
:return: the corresponding derivative matrix
'''
pass
[docs]class ProductOfMean(Mean):
'''Product of two mean fucntions.'''
def __init__(self,mean1,mean2):
self.mean1 = mean1
self.mean2 = mean2
if mean1.hyp and mean2.hyp:
self._hyp = mean1.hyp + mean2.hyp
elif not mean1.hyp:
self._hyp = mean2.hyp
elif not mean2.hyp:
self._hyp = mean1.hyp
def _setHyp(self,hyp):
assert len(hyp) == len(self._hyp)
len1 = len(self.mean1.hyp)
self._hyp = hyp
self.mean1.hyp = self._hyp[:len1]
self.mean2.hyp = self._hyp[len1:]
def _getHyp(self):
return self._hyp
hyp = property(_getHyp,_setHyp)
def getMean(self, x=None):
A = self.mean1.getMean(x) * self.mean2.getMean(x)
return A
def getDerMatrix(self, x=None, der=None):
if der < len(self.mean1.hyp):
A = self.mean1.getDerMatrix(x, der) * self.mean2.getMean(x)
elif der < len(self.hyp):
der2 = der - len(self.mean1.hyp)
A = self.mean2.getDerMatrix(x, der2) * self.mean1.getMean(x)
else:
raise Exception("Error: der out of range for meanProduct")
return A
[docs]class SumOfMean(Mean):
'''Sum of two mean functions.'''
def __init__(self,mean1,mean2):
self.mean1 = mean1
self.mean2 = mean2
if mean1.hyp and mean2.hyp:
self._hyp = mean1.hyp + mean2.hyp
elif not mean1.hyp:
self._hyp = mean2.hyp
elif not mean2.hyp:
self._hyp = mean1.hyp
def _setHyp(self,hyp):
assert len(hyp) == len(self._hyp)
len1 = len(self.mean1.hyp)
self._hyp = hyp
self.mean1.hyp = self._hyp[:len1]
self.mean2.hyp = self._hyp[len1:]
def _getHyp(self):
return self._hyp
hyp = property(_getHyp,_setHyp)
def getMean(self, x=None):
A = self.mean1.getMean(x) + self.mean2.getMean(x)
return A
def getDerMatrix(self, x=None, der=None):
if der < len(self.mean1.hyp):
A = self.mean1.getDerMatrix(x, der)
elif der < len(self.hyp):
der2 = der - len(self.mean1.hyp)
A = self.mean2.getDerMatrix(x, der2)
else:
raise Exception("Error: der out of range for meanSum")
return A
[docs]class ScaleOfMean(Mean):
'''Scale of a mean function.'''
def __init__(self,mean,scalar):
self.mean = mean
if mean.hyp:
self._hyp = [scalar] + mean.hyp
else:
self._hyp = [scalar]
def _setHyp(self,hyp):
assert len(hyp) == len(self._hyp)
self._hyp = hyp
self.mean.hyp = self._hyp[1:]
def _getHyp(self):
return self._hyp
hyp = property(_getHyp,_setHyp)
def getMean(self, x=None):
c = self.hyp[0] # scale parameter
A = c * self.mean.getMean(x) # accumulate means
return A
def getDerMatrix(self, x=None, der=None):
c = self.hyp[0] # scale parameter
if der == 0: # compute derivative w.r.t. c
A = self.mean.getMean(x)
else:
A = c * self.mean.getDerMatrix(x,der-1)
return A
[docs]class PowerOfMean(Mean):
'''Power of a mean fucntion.'''
def __init__(self, mean, d):
self.mean = mean
if mean.hyp:
self._hyp = [d] + mean.hyp
else:
self._hyp = [d]
def _setHyp(self,hyp):
assert len(hyp) == len(self._hyp)
self._hyp = hyp
self.mean.hyp = self._hyp[1:]
def _getHyp(self):
return self._hyp
hyp = property(_getHyp,_setHyp)
def getMean(self, x=None):
d = np.abs(np.floor(self.hyp[0]))
d = max(d,1)
A = self.mean.getMean(x) **d # accumulate means
return A
def getDerMatrix(self, x=None, der=None):
d = np.abs(np.floor(self.hyp[0]))
d = max(d,1)
if der == 0: # compute derivative w.r.t. c
a = self.mean.getMean(x)
A = a**d * np.log(a)
else:
A = d * self.mean.getMean(x) ** (d-1) * self.mean.getDerMatrix(x, der-1)
return A
[docs]class Zero(Mean):
'''Zero mean.'''
def __init__(self):
self.hyp = []
self.name = '0'
def getMean(self, x=None):
n, D = x.shape
A = np.zeros((n,1))
return A
def getDerMatrix(self, x=None, der=None):
n, D = x.shape
A = np.zeros((n,1))
return A
[docs]class One(Mean):
''' One mean.'''
def __init__(self):
self.hyp = []
self.name = '1'
def getMean(self, x=None):
n, D = x.shape
A = np.ones((n,1))
return A
def getDerMatrix(self, x=None, der=None):
n, D = x.shape
A = np.zeros((n,1))
return A
[docs]class Const(Mean):
'''
Constant mean function. hyp = [c]
:param c: constant value for mean
'''
def __init__(self, c=5.):
self.hyp = [c]
def getMean(self, x=None):
n,D = x.shape
A = self.hyp[0] * np.ones((n,1))
return A
def getDerMatrix(self, x=None, der=None):
n,D = x.shape
if der == 0: # compute derivative vector wrt c
A = np.ones((n,1))
else:
A = np.zeros((n,1))
return A
[docs]class Linear(Mean):
'''
Linear mean function. self.hyp = alpha_list
:param D: dimension of training data. Set if you want default alpha, which is 0.5 for each dimension.
:alpha_list: scalar alpha for each dimension
'''
def __init__(self, D=None, alpha_list=None):
if alpha_list is None:
if D is None:
self.hyp = [0.5]
else:
self.hyp = [0.5 for i in xrange(D)]
else:
self.hyp = alpha_list
def getMean(self, x=None):
n, D = x.shape
c = np.array(self.hyp)
c = np.reshape(c,(len(c),1))
A = np.dot(x,c)
return A
def getDerMatrix(self, x=None, der=None):
n, D = x.shape
c = np.array(self.hyp)
c = np.reshape(c,(len(c),1))
if isinstance(der, int) and der < D: # compute derivative vector wrt meanparameters
A = np.reshape(x[:,der], (len(x[:,der]),1) )
else:
A = np.zeros((n,1))
return A
if __name__ == '__main__':
pass