Using params class with sympy covariance. Adding conditional statements for presence of weave.

This commit is contained in:
Neil Lawrence 2014-02-18 19:37:53 -05:00
parent d1b6d18ddf
commit f6484bcbd0

View file

@ -1,17 +1,31 @@
import numpy as np try:
import sympy as sp import sympy as sp
from sympy.utilities.codegen import codegen sympy_available=True
from sympy.core.cache import clear_cache except ImportError:
sympy_available=False
exit()
from sympy.core.cache import clear_cache
from sympy.utilities.codegen import codegen
try:
from scipy import weave
weave_available = True
except ImportError:
weave_available = False
from scipy import weave
import re
import os import os
import sys
current_dir = os.path.dirname(os.path.abspath(os.path.dirname(__file__))) current_dir = os.path.dirname(os.path.abspath(os.path.dirname(__file__)))
import sys
import numpy as np
import re
import tempfile import tempfile
import pdb import pdb
import ast import ast
from kernpart import Kernpart from kernpart import Kernpart
from ...core.parameterization import Param
from ...core.parameterization.transformations import Logexp
class spkern(Kernpart): class spkern(Kernpart):
""" """
@ -75,17 +89,20 @@ class spkern(Kernpart):
self.num_split_params = len(self._sp_theta_i) self.num_split_params = len(self._sp_theta_i)
self._split_theta_names = ["%s"%theta.name[:-2] for theta in self._sp_theta_i] self._split_theta_names = ["%s"%theta.name[:-2] for theta in self._sp_theta_i]
for theta in self._split_theta_names: for theta in self._split_theta_names:
setattr(self, theta, np.ones(self.output_dim)) setattr(self, theta, Param(theta, np.ones(self.output_dim), None))
self.add_parameters(getattr(self, theta))
#setattr(self, theta, np.ones(self.output_dim))
self.num_shared_params = len(self._sp_theta) self.num_shared_params = len(self._sp_theta)
self.num_params = self.num_shared_params+self.num_split_params*self.output_dim #self.num_params = self.num_shared_params+self.num_split_params*self.output_dim
else: else:
self.num_split_params = 0 self.num_split_params = 0
self._split_theta_names = [] self._split_theta_names = []
self._sp_theta = thetas self._sp_theta = thetas
self.num_shared_params = len(self._sp_theta) self.num_shared_params = len(self._sp_theta)
self.num_params = self.num_shared_params #self.num_params = self.num_shared_params
# Add parameters to the model. # Add parameters to the model.
for theta in self._sp_theta: for theta in self._sp_theta:
@ -93,9 +110,12 @@ class spkern(Kernpart):
if param is not None: if param is not None:
if param.has_key(theta): if param.has_key(theta):
val = param[theta] val = param[theta]
setattr(self, theta.name, val) #setattr(self, theta.name, val)
setattr(self, theta.name, Param(theta.name, val, None))
self.add_parameters(getattr(self, theta.name))
self.parameters_changed() # initializes cache
#deal with param #deal with param
self._set_params(self._get_params()) #self._set_params(self._get_params())
# Differentiate with respect to parameters. # Differentiate with respect to parameters.
self._sp_dk_dtheta = [sp.diff(k,theta).simplify() for theta in self._sp_theta] self._sp_dk_dtheta = [sp.diff(k,theta).simplify() for theta in self._sp_theta]
@ -112,26 +132,26 @@ class spkern(Kernpart):
# generate the code for the covariance functions # generate the code for the covariance functions
self._gen_code() self._gen_code()
if weave if weave_available:
if False: if False:
extra_compile_args = ['-ftree-vectorize', '-mssse3', '-ftree-vectorizer-verbose=5'] extra_compile_args = ['-ftree-vectorize', '-mssse3', '-ftree-vectorizer-verbose=5']
else: else:
extra_compile_args = [] extra_compile_args = []
self.weave_kwargs = { self.weave_kwargs = {
'support_code':self._function_code, 'support_code':self._function_code,
'include_dirs':[tempfile.gettempdir(), os.path.join(current_dir,'parts/')], 'include_dirs':[tempfile.gettempdir(), os.path.join(current_dir,'parts/')],
'headers':['"sympy_helpers.h"'], 'headers':['"sympy_helpers.h"'],
'sources':[os.path.join(current_dir,"parts/sympy_helpers.cpp")], 'sources':[os.path.join(current_dir,"parts/sympy_helpers.cpp")],
'extra_compile_args':extra_compile_args, 'extra_compile_args':extra_compile_args,
'extra_link_args':['-lgomp'], 'extra_link_args':['-lgomp'],
'verbose':True} 'verbose':True}
def __add__(self,other): def __add__(self,other):
return spkern(self._sp_k+other._sp_k) return spkern(self._sp_k+other._sp_k)
def _gen_code(self): def _gen_code(self):
#generate c functions from sympy objects
argument_sequence = self._sp_x+self._sp_z+self._sp_theta argument_sequence = self._sp_x+self._sp_z+self._sp_theta
code_list = [('k',self._sp_k)] code_list = [('k',self._sp_k)]
# gradients with respect to covariance input # gradients with respect to covariance input
@ -142,193 +162,224 @@ class spkern(Kernpart):
if self.output_dim > 1: if self.output_dim > 1:
argument_sequence += self._sp_theta_i + self._sp_theta_j argument_sequence += self._sp_theta_i + self._sp_theta_j
code_list += [('dk_d%s'%theta.name,dtheta) for theta,dtheta in zip(self._sp_theta_i,self._sp_dk_dtheta_i)] code_list += [('dk_d%s'%theta.name,dtheta) for theta,dtheta in zip(self._sp_theta_i,self._sp_dk_dtheta_i)]
# generate c functions from sympy objects
if weave_available:
code_type = "C"
else:
code_type = "PYTHON"
(foo_c,self._function_code), (foo_h,self._function_header) = \ (foo_c,self._function_code), (foo_h,self._function_header) = \
codegen(code_list, "C",'foobar',argument_sequence=argument_sequence) codegen(code_list,
#put the header file where we can find it code_type,
f = file(os.path.join(tempfile.gettempdir(),'foobar.h'),'w') self.name,
f.write(self._function_header) argument_sequence=argument_sequence)
f.close()
# Use weave to compute the underlying functions.
if weave_available:
# put the header file where we can find it
f = file(os.path.join(tempfile.gettempdir(), self.name + '.h'),'w')
f.write(self._function_header)
f.close()
# Substitute any known derivatives which sympy doesn't compute # Substitute any known derivatives which sympy doesn't compute
self._function_code = re.sub('DiracDelta\(.+?,.+?\)','0.0',self._function_code) self._function_code = re.sub('DiracDelta\(.+?,.+?\)','0.0',self._function_code)
# This is the basic argument construction for the C code. if weave_available:
#arg_list = (["X[i*input_dim+%s]"%x.name[2:] for x in self._sp_x] # arg_list will store the arguments required for the C code.
# + ["Z[j*input_dim+%s]"%z.name[2:] for z in self._sp_z]) arg_list = (["X2(i, %s)"%x.name[2:] for x in self._sp_x]
arg_list = (["X2(i, %s)"%x.name[2:] for x in self._sp_x] + ["Z2(j, %s)"%z.name[2:] for z in self._sp_z])
+ ["Z2(j, %s)"%z.name[2:] for z in self._sp_z])
if self.output_dim>1:
reverse_arg_list = list(arg_list)
reverse_arg_list.reverse()
param_arg_list = [shared_params.name for shared_params in self._sp_theta] # for multiple outputs reverse argument list is also required
arg_list += param_arg_list if self.output_dim>1:
reverse_arg_list = list(arg_list)
reverse_arg_list.reverse()
precompute_list=[] # This gives the parameters for the arg list.
if self.output_dim > 1: param_arg_list = [shared_params.name for shared_params in self._sp_theta]
reverse_arg_list+=list(param_arg_list) arg_list += param_arg_list
split_param_arg_list = ["%s1(%s)"%(theta.name[:-2].upper(),index) for index in ['ii', 'jj'] for theta in self._sp_theta_i]
split_param_reverse_arg_list = ["%s1(%s)"%(theta.name[:-2].upper(),index) for index in ['jj', 'ii'] for theta in self._sp_theta_i] precompute_list=[]
arg_list += split_param_arg_list if self.output_dim > 1:
reverse_arg_list += split_param_reverse_arg_list reverse_arg_list+=list(param_arg_list)
# Extract the right output indices from the inputs. # For multiple outputs, also need the split parameters.
c_define_output_indices = [' '*16 + "int %s=(int)%s(%s, %i);"%(index, var, index2, self.input_dim-1) for index, var, index2 in zip(['ii', 'jj'], ['X2', 'Z2'], ['i', 'j'])] split_param_arg_list = ["%s1(%s)"%(theta.name[:-2].upper(),index) for index in ['ii', 'jj'] for theta in self._sp_theta_i]
precompute_list += c_define_output_indices split_param_reverse_arg_list = ["%s1(%s)"%(theta.name[:-2].upper(),index) for index in ['jj', 'ii'] for theta in self._sp_theta_i]
reverse_arg_string = ", ".join(reverse_arg_list) arg_list += split_param_arg_list
arg_string = ", ".join(arg_list) reverse_arg_list += split_param_reverse_arg_list
precompute_string = "\n".join(precompute_list) # Extract the right output indices from the inputs.
# Here's the code to do the looping for K c_define_output_indices = [' '*16 + "int %s=(int)%s(%s, %i);"%(index, var, index2, self.input_dim-1) for index, var, index2 in zip(['ii', 'jj'], ['X2', 'Z2'], ['i', 'j'])]
self._K_code =\ precompute_list += c_define_output_indices
""" reverse_arg_string = ", ".join(reverse_arg_list)
// _K_code arg_string = ", ".join(arg_list)
// Code for computing the covariance function. precompute_string = "\n".join(precompute_list)
int i;
int j; # Now we use the arguments in code that computes the separate parts.
int N = target_array->dimensions[0];
int num_inducing = target_array->dimensions[1]; # Any precomputations will be done here eventually.
int input_dim = X_array->dimensions[1]; self._precompute = \
//#pragma omp parallel for private(j) """
for (i=0;i<N;i++){ // Precompute code would go here. It will be called when parameters are updated.
for (j=0;j<num_inducing;j++){ """
%s
//target[i*num_inducing+j] = # Here's the code to do the looping for K
TARGET2(i, j) += k(%s); self._K_code =\
"""
// _K_code
// Code for computing the covariance function.
int i;
int j;
int N = target_array->dimensions[0];
int num_inducing = target_array->dimensions[1];
int input_dim = X_array->dimensions[1];
//#pragma omp parallel for private(j)
for (i=0;i<N;i++){
for (j=0;j<num_inducing;j++){
%s
//target[i*num_inducing+j] =
TARGET2(i, j) += k(%s);
}
} }
} %s
%s """%(precompute_string,arg_string,"/*"+str(self._sp_k)+"*/")
"""%(precompute_string,arg_string,"/*"+str(self._sp_k)+"*/") #adding a string representation forces recompile when needed # adding a string representation of the function in the
# comment forces recompile when needed
# Code to compute diagonal of covariance.
diag_arg_string = re.sub('Z','X',arg_string)
diag_arg_string = re.sub('int jj','//int jj',diag_arg_string)
diag_arg_string = re.sub('j','i',diag_arg_string)
diag_precompute_string = re.sub('int jj','//int jj',precompute_string)
diag_precompute_string = re.sub('Z','X',diag_precompute_string)
diag_precompute_string = re.sub('j','i',diag_precompute_string)
# Code to do the looping for Kdiag
self._Kdiag_code =\
"""
// _Kdiag_code
// Code for computing diagonal of covariance function.
int i;
int N = target_array->dimensions[0];
int input_dim = X_array->dimensions[1];
//#pragma omp parallel for
for (i=0;i<N;i++){
%s
//target[i] =
TARGET1(i)=k(%s);
}
%s
"""%(diag_precompute_string,diag_arg_string,"/*"+str(self._sp_k)+"*/") #adding a string representation forces recompile when needed
# Code to compute gradients # Code to compute diagonal of covariance.
grad_func_list = [] diag_arg_string = re.sub('Z','X',arg_string)
if self.output_dim>1: diag_arg_string = re.sub('int jj','//int jj',diag_arg_string)
grad_func_list += c_define_output_indices diag_arg_string = re.sub('j','i',diag_arg_string)
grad_func_list += [' '*16 + 'TARGET1(%i+ii) += partial[i*num_inducing+j]*dk_d%s(%s);'%(self.num_shared_params+i*self.output_dim, theta.name, arg_string) for i, theta in enumerate(self._sp_theta_i)] diag_precompute_string = re.sub('int jj','//int jj',precompute_string)
grad_func_list += [' '*16 + 'TARGET1(%i+jj) += partial[i*num_inducing+j]*dk_d%s(%s);'%(self.num_shared_params+i*self.output_dim, theta.name, reverse_arg_string) for i, theta in enumerate(self._sp_theta_i)] diag_precompute_string = re.sub('Z','X',diag_precompute_string)
grad_func_list += ([' '*16 + 'TARGET1(%i) += partial[i*num_inducing+j]*dk_d%s(%s);'%(i,theta.name,arg_string) for i,theta in enumerate(self._sp_theta)]) diag_precompute_string = re.sub('j','i',diag_precompute_string)
grad_func_string = '\n'.join(grad_func_list) # Code to do the looping for Kdiag
self._Kdiag_code =\
self._dK_dtheta_code =\ """
""" // _Kdiag_code
// _dK_dtheta_code // Code for computing diagonal of covariance function.
// Code for computing gradient of covariance with respect to parameters. int i;
int i; int N = target_array->dimensions[0];
int j; int input_dim = X_array->dimensions[1];
int N = partial_array->dimensions[0]; //#pragma omp parallel for
int num_inducing = partial_array->dimensions[1]; for (i=0;i<N;i++){
int input_dim = X_array->dimensions[1]; %s
//#pragma omp parallel for private(j) //target[i] =
for (i=0;i<N;i++){ TARGET1(i)=k(%s);
for (j=0;j<num_inducing;j++){
%s
} }
} %s
%s """%(diag_precompute_string,diag_arg_string,"/*"+str(self._sp_k)+"*/") #adding a string representation forces recompile when needed
"""%(grad_func_string,"/*"+str(self._sp_k)+"*/") # adding a string representation forces recompile when needed
# Code to compute gradients
grad_func_list = []
if self.output_dim>1:
grad_func_list += c_define_output_indices
grad_func_list += [' '*16 + 'TARGET1(%i+ii) += partial[i*num_inducing+j]*dk_d%s(%s);'%(self.num_shared_params+i*self.output_dim, theta.name, arg_string) for i, theta in enumerate(self._sp_theta_i)]
grad_func_list += [' '*16 + 'TARGET1(%i+jj) += partial[i*num_inducing+j]*dk_d%s(%s);'%(self.num_shared_params+i*self.output_dim, theta.name, reverse_arg_string) for i, theta in enumerate(self._sp_theta_i)]
grad_func_list += ([' '*16 + 'TARGET1(%i) += partial[i*num_inducing+j]*dk_d%s(%s);'%(i,theta.name,arg_string) for i,theta in enumerate(self._sp_theta)])
grad_func_string = '\n'.join(grad_func_list)
self._dK_dtheta_code =\
"""
// _dK_dtheta_code
// Code for computing gradient of covariance with respect to parameters.
int i;
int j;
int N = partial_array->dimensions[0];
int num_inducing = partial_array->dimensions[1];
int input_dim = X_array->dimensions[1];
//#pragma omp parallel for private(j)
for (i=0;i<N;i++){
for (j=0;j<num_inducing;j++){
%s
}
}
%s
"""%(grad_func_string,"/*"+str(self._sp_k)+"*/") # adding a string representation forces recompile when needed
# Code to compute gradients for Kdiag TODO: needs clean up # Code to compute gradients for Kdiag TODO: needs clean up
diag_grad_func_string = re.sub('Z','X',grad_func_string,count=0) diag_grad_func_string = re.sub('Z','X',grad_func_string,count=0)
diag_grad_func_string = re.sub('int jj','//int jj',diag_grad_func_string) diag_grad_func_string = re.sub('int jj','//int jj',diag_grad_func_string)
diag_grad_func_string = re.sub('j','i',diag_grad_func_string) diag_grad_func_string = re.sub('j','i',diag_grad_func_string)
diag_grad_func_string = re.sub('partial\[i\*num_inducing\+i\]','partial[i]',diag_grad_func_string) diag_grad_func_string = re.sub('partial\[i\*num_inducing\+i\]','partial[i]',diag_grad_func_string)
self._dKdiag_dtheta_code =\ self._dKdiag_dtheta_code =\
""" """
// _dKdiag_dtheta_code // _dKdiag_dtheta_code
// Code for computing gradient of diagonal with respect to parameters. // Code for computing gradient of diagonal with respect to parameters.
int i; int i;
int N = partial_array->dimensions[0]; int N = partial_array->dimensions[0];
int input_dim = X_array->dimensions[1]; int input_dim = X_array->dimensions[1];
for (i=0;i<N;i++){ for (i=0;i<N;i++){
%s
}
%s
"""%(diag_grad_func_string,"/*"+str(self._sp_k)+"*/") #adding a string representation forces recompile when needed
# Code for gradients wrt X, TODO: may need to deal with special case where one input is actually an output.
gradX_func_list = []
if self.output_dim>1:
gradX_func_list += c_define_output_indices
gradX_func_list += ["TARGET2(i, %i) += partial[i*num_inducing+j]*dk_dx_%i(%s);"%(q,q,arg_string) for q in range(self._real_input_dim)]
gradX_func_string = "\n".join(gradX_func_list)
self._dK_dX_code = \
"""
// _dK_dX_code
// Code for computing gradient of covariance with respect to inputs.
int i;
int j;
int N = partial_array->dimensions[0];
int num_inducing = partial_array->dimensions[1];
int input_dim = X_array->dimensions[1];
//#pragma omp parallel for private(j)
for (i=0;i<N; i++){
for (j=0; j<num_inducing; j++){
%s %s
} }
%s }
"""%(diag_grad_func_string,"/*"+str(self._sp_k)+"*/") #adding a string representation forces recompile when needed
# Code for gradients wrt X, TODO: may need to deal with special case where one input is actually an output.
gradX_func_list = []
if self.output_dim>1:
gradX_func_list += c_define_output_indices
gradX_func_list += ["TARGET2(i, %i) += partial[i*num_inducing+j]*dk_dx_%i(%s);"%(q,q,arg_string) for q in range(self._real_input_dim)]
gradX_func_string = "\n".join(gradX_func_list)
self._dK_dX_code = \
"""
// _dK_dX_code
// Code for computing gradient of covariance with respect to inputs.
int i;
int j;
int N = partial_array->dimensions[0];
int num_inducing = partial_array->dimensions[1];
int input_dim = X_array->dimensions[1];
//#pragma omp parallel for private(j)
for (i=0;i<N; i++){
for (j=0; j<num_inducing; j++){
%s %s
} """%(gradX_func_string,"/*"+str(self._sp_k)+"*/") #adding a string representation forces recompile when needed
}
%s
"""%(gradX_func_string,"/*"+str(self._sp_k)+"*/") #adding a string representation forces recompile when needed
diag_gradX_func_string = re.sub('Z','X',gradX_func_string,count=0)
diag_gradX_func_string = re.sub('int jj','//int jj',diag_gradX_func_string)
diag_gradX_func_string = re.sub('j','i',diag_gradX_func_string)
diag_gradX_func_string = re.sub('partial\[i\*num_inducing\+i\]','2*partial[i]',diag_gradX_func_string)
# Code for gradients of Kdiag wrt X diag_gradX_func_string = re.sub('Z','X',gradX_func_string,count=0)
self._dKdiag_dX_code= \ diag_gradX_func_string = re.sub('int jj','//int jj',diag_gradX_func_string)
""" diag_gradX_func_string = re.sub('j','i',diag_gradX_func_string)
// _dKdiag_dX_code diag_gradX_func_string = re.sub('partial\[i\*num_inducing\+i\]','2*partial[i]',diag_gradX_func_string)
// Code for computing gradient of diagonal with respect to inputs.
int N = partial_array->dimensions[0]; # Code for gradients of Kdiag wrt X
int input_dim = X_array->dimensions[1]; self._dKdiag_dX_code= \
for (int i=0;i<N; i++){ """
// _dKdiag_dX_code
// Code for computing gradient of diagonal with respect to inputs.
int N = partial_array->dimensions[0];
int input_dim = X_array->dimensions[1];
for (int i=0;i<N; i++){
%s
}
%s %s
} """%(diag_gradX_func_string,"/*"+str(self._sp_k)+"*/") #adding a
%s # string representation forces recompile when needed Get rid
"""%(diag_gradX_func_string,"/*"+str(self._sp_k)+"*/") #adding a # of Zs in argument for diagonal. TODO: Why wasn't
# string representation forces recompile when needed Get rid # diag_func_string called here? Need to check that.
# of Zs in argument for diagonal. TODO: Why wasn't #self._dKdiag_dX_code = self._dKdiag_dX_code.replace('Z[j', 'X[i')
# diag_func_string called here? Need to check that.
#self._dKdiag_dX_code = self._dKdiag_dX_code.replace('Z[j', 'X[i')
# Code to use when only X is provided. # Code to use when only X is provided.
self._K_code_X = self._K_code.replace('Z[', 'X[') self._K_code_X = self._K_code.replace('Z[', 'X[')
self._dK_dtheta_code_X = self._dK_dtheta_code.replace('Z[', 'X[') self._dK_dtheta_code_X = self._dK_dtheta_code.replace('Z[', 'X[')
self._dK_dX_code_X = self._dK_dX_code.replace('Z[', 'X[').replace('+= partial[', '+= 2*partial[') self._dK_dX_code_X = self._dK_dX_code.replace('Z[', 'X[').replace('+= partial[', '+= 2*partial[')
self._K_code_X = self._K_code.replace('Z2(', 'X2(') self._K_code_X = self._K_code.replace('Z2(', 'X2(')
self._dK_dtheta_code_X = self._dK_dtheta_code.replace('Z2(', 'X2(') self._dK_dtheta_code_X = self._dK_dtheta_code.replace('Z2(', 'X2(')
self._dK_dX_code_X = self._dK_dX_code.replace('Z2(', 'X2(') self._dK_dX_code_X = self._dK_dX_code.replace('Z2(', 'X2(')
#TODO: insert multiple functions here via string manipulation #TODO: insert multiple functions here via string manipulation
#TODO: similar functions for psi_stats #TODO: similar functions for psi_stats
#TODO: similar functions when cython available.
#TODO: similar functions when only python available.
def _get_arg_names(self, Z=None, partial=None): def _get_arg_names(self, Z=None, partial=None):
arg_names = ['target','X'] arg_names = ['target','X']
for shared_params in self._sp_theta: for shared_params in self._sp_theta:
arg_names += [shared_params.name] arg_names += [shared_params.name]
@ -340,8 +391,8 @@ class spkern(Kernpart):
arg_names += self._split_theta_names arg_names += self._split_theta_names
arg_names += ['output_dim'] arg_names += ['output_dim']
return arg_names return arg_names
def _weave_inline(self, code, X, target, Z=None, partial=None): def _generate_inline(self, code, X, target, Z=None, partial=None):
output_dim = self.output_dim output_dim = self.output_dim
for shared_params in self._sp_theta: for shared_params in self._sp_theta:
locals()[shared_params.name] = getattr(self, shared_params.name) locals()[shared_params.name] = getattr(self, shared_params.name)
@ -350,35 +401,38 @@ class spkern(Kernpart):
for split_params in self._split_theta_names: for split_params in self._split_theta_names:
locals()[split_params] = getattr(self, split_params) locals()[split_params] = getattr(self, split_params)
arg_names = self._get_arg_names(Z, partial) arg_names = self._get_arg_names(Z, partial)
weave.inline(code=code, arg_names=arg_names,**self.weave_kwargs) if weave_available:
weave.inline(code=code, arg_names=arg_names,**self.weave_kwargs)
else:
raise RuntimeError('Weave not available and other variants of sympy covariance not yet implemented')
def K(self,X,Z,target): def K(self,X,Z,target):
if Z is None: if Z is None:
self._weave_inline(self._K_code_X, X, target) self._generate_inline(self._K_code_X, X, target)
else: else:
self._weave_inline(self._K_code, X, target, Z) self._generate_inline(self._K_code, X, target, Z)
def Kdiag(self,X,target): def Kdiag(self,X,target):
self._weave_inline(self._Kdiag_code, X, target) self._generate_inline(self._Kdiag_code, X, target)
def _param_grad_helper(self,partial,X,Z,target): def _param_grad_helper(self,partial,X,Z,target):
if Z is None: if Z is None:
self._weave_inline(self._dK_dtheta_code_X, X, target, Z, partial) self._generate_inline(self._dK_dtheta_code_X, X, target, Z, partial)
else: else:
self._weave_inline(self._dK_dtheta_code, X, target, Z, partial) self._generate_inline(self._dK_dtheta_code, X, target, Z, partial)
def dKdiag_dtheta(self,partial,X,target): def dKdiag_dtheta(self,partial,X,target):
self._weave_inline(self._dKdiag_dtheta_code, X, target, Z=None, partial=partial) self._generate_inline(self._dKdiag_dtheta_code, X, target, Z=None, partial=partial)
def gradients_X(self,partial,X,Z,target): def gradients_X(self,partial,X,Z,target):
if Z is None: if Z is None:
self._weave_inline(self._dK_dX_code_X, X, target, Z, partial) self._generate_inline(self._dK_dX_code_X, X, target, Z, partial)
else: else:
self._weave_inline(self._dK_dX_code, X, target, Z, partial) self._generate_inline(self._dK_dX_code, X, target, Z, partial)
def dKdiag_dX(self,partial,X,target): def dKdiag_dX(self,partial,X,target):
self._weave.inline(self._dKdiag_dX_code, X, target, Z, partial) self._generate_inline(self._dKdiag_dX_code, X, target, Z, partial)
def compute_psi_stats(self): def compute_psi_stats(self):
#define some normal distributions #define some normal distributions
@ -407,31 +461,34 @@ class spkern(Kernpart):
self._sp_psi2 = sp.integrate(self._sp_psi2,(self._sp_x[i],-sp.oo,sp.oo)) self._sp_psi2 = sp.integrate(self._sp_psi2,(self._sp_x[i],-sp.oo,sp.oo))
clear_cache() clear_cache()
self._sp_psi2 = self._sp_psi2.simplify() self._sp_psi2 = self._sp_psi2.simplify()
def parameters_changed(self):
# Do anything here that needs to happen when parameters change, like precompute.
self._generate_inline(self._precompute, X, target, Z, partial)
def _set_params(self,param): # def _set_params(self,param):
assert param.size == (self.num_params) # assert param.size == (self.num_params)
for i, shared_params in enumerate(self._sp_theta): # for i, shared_params in enumerate(self._sp_theta):
setattr(self, shared_params.name, param[i]) # setattr(self, shared_params.name, param[i])
if self.output_dim>1: # if self.output_dim>1:
for i, split_params in enumerate(self._split_theta_names): # for i, split_params in enumerate(self._split_theta_names):
start = self.num_shared_params + i*self.output_dim # start = self.num_shared_params + i*self.output_dim
end = self.num_shared_params + (i+1)*self.output_dim # end = self.num_shared_params + (i+1)*self.output_dim
setattr(self, split_params, param[start:end]) # setattr(self, split_params, param[start:end])
def _get_params(self): # def _get_params(self):
params = np.zeros(0) # params = np.zeros(0)
for shared_params in self._sp_theta: # for shared_params in self._sp_theta:
params = np.hstack((params, getattr(self, shared_params.name))) # params = np.hstack((params, getattr(self, shared_params.name)))
if self.output_dim>1: # if self.output_dim>1:
for split_params in self._split_theta_names: # for split_params in self._split_theta_names:
params = np.hstack((params, getattr(self, split_params).flatten())) # params = np.hstack((params, getattr(self, split_params).flatten()))
return params # return params
def _get_param_names(self): # def _get_param_names(self):
if self.output_dim>1: # if self.output_dim>1:
return [x.name for x in self._sp_theta] + [x.name[:-2] + str(i) for x in self._sp_theta_i for i in range(self.output_dim)] # return [x.name for x in self._sp_theta] + [x.name[:-2] + str(i) for x in self._sp_theta_i for i in range(self.output_dim)]
else: # else:
return [x.name for x in self._sp_theta] # return [x.name for x in self._sp_theta]