REFACTORING: model names, lowercase, classes uppercase

This commit is contained in:
Max Zwiessele 2013-06-05 13:02:03 +01:00
parent 2a39440619
commit 2e5e8ac026
50 changed files with 436 additions and 3307 deletions

View file

@ -1,87 +1,80 @@
# Copyright (c) 2012, GPy authors (see AUTHORS.txt).
# Licensed under the BSD 3-clause license (see LICENSE.txt)
#tdot function courtesy of Ian Murray:
# tdot function courtesy of Ian Murray:
# Iain Murray, April 2013. iain contactable via iainmurray.net
# http://homepages.inf.ed.ac.uk/imurray2/code/tdot/tdot.py
import numpy as np
from scipy import linalg, optimize, weave
import pylab as pb
import Tango
import sys
import re
import pdb
import cPickle
from scipy import linalg, weave
import types
import ctypes
from ctypes import byref, c_char, c_int, c_double # TODO
#import scipy.lib.lapack
import scipy as sp
# import scipy.lib.lapack
try:
_blaslib = ctypes.cdll.LoadLibrary(np.core._dotblas.__file__)
_blaslib = ctypes.cdll.LoadLibrary(np.core._dotblas.__file__) # @UndefinedVariable
_blas_available = True
except:
_blas_available = False
def trace_dot(a,b):
def trace_dot(a, b):
"""
efficiently compute the trace of the matrix product of a and b
"""
return np.sum(a*b)
return np.sum(a * b)
def mdot(*args):
"""Multiply all the arguments using matrix product rules.
The output is equivalent to multiplying the arguments one by one
from left to right using dot().
Precedence can be controlled by creating tuples of arguments,
for instance mdot(a,((b,c),d)) multiplies a (a*((b*c)*d)).
Note that this means the output of dot(a,b) and mdot(a,b) will differ if
a or b is a pure tuple of numbers.
"""
if len(args)==1:
return args[0]
elif len(args)==2:
return _mdot_r(args[0],args[1])
else:
return _mdot_r(args[:-1],args[-1])
"""Multiply all the arguments using matrix product rules.
The output is equivalent to multiplying the arguments one by one
from left to right using dot().
Precedence can be controlled by creating tuples of arguments,
for instance mdot(a,((b,c),d)) multiplies a (a*((b*c)*d)).
Note that this means the output of dot(a,b) and mdot(a,b) will differ if
a or b is a pure tuple of numbers.
"""
if len(args) == 1:
return args[0]
elif len(args) == 2:
return _mdot_r(args[0], args[1])
else:
return _mdot_r(args[:-1], args[-1])
def _mdot_r(a,b):
"""Recursive helper for mdot"""
if type(a)==types.TupleType:
if len(a)>1:
a = mdot(*a)
else:
a = a[0]
if type(b)==types.TupleType:
if len(b)>1:
b = mdot(*b)
else:
b = b[0]
return np.dot(a,b)
def _mdot_r(a, b):
"""Recursive helper for mdot"""
if type(a) == types.TupleType:
if len(a) > 1:
a = mdot(*a)
else:
a = a[0]
if type(b) == types.TupleType:
if len(b) > 1:
b = mdot(*b)
else:
b = b[0]
return np.dot(a, b)
def jitchol(A,maxtries=5):
def jitchol(A, maxtries=5):
A = np.asfortranarray(A)
L,info = linalg.lapack.flapack.dpotrf(A,lower=1)
if info ==0:
L, info = linalg.lapack.flapack.dpotrf(A, lower=1)
if info == 0:
return L
else:
diagA = np.diag(A)
if np.any(diagA<0.):
if np.any(diagA < 0.):
raise linalg.LinAlgError, "not pd: negative diagonal elements"
jitter= diagA.mean()*1e-6
for i in range(1,maxtries+1):
jitter = diagA.mean() * 1e-6
for i in range(1, maxtries + 1):
print 'Warning: adding jitter of {:.10e}'.format(jitter)
try:
return linalg.cholesky(A+np.eye(A.shape[0]).T*jitter, lower = True)
return linalg.cholesky(A + np.eye(A.shape[0]).T * jitter, lower=True)
except:
jitter *= 10
raise linalg.LinAlgError,"not positive definite, even with jitter."
raise linalg.LinAlgError, "not positive definite, even with jitter."
def jitchol_old(A,maxtries=5):
def jitchol_old(A, maxtries=5):
"""
:param A : An almost pd square matrix
@ -93,20 +86,20 @@ def jitchol_old(A,maxtries=5):
np.allclose(sp.linalg.cholesky(XXT, lower = True), np.triu(sp.linalg.cho_factor(XXT)[0]).T)
"""
try:
return linalg.cholesky(A, lower = True)
return linalg.cholesky(A, lower=True)
except linalg.LinAlgError:
diagA = np.diag(A)
if np.any(diagA<0.):
if np.any(diagA < 0.):
raise linalg.LinAlgError, "not pd: negative diagonal elements"
jitter= diagA.mean()*1e-6
for i in range(1,maxtries+1):
jitter = diagA.mean() * 1e-6
for i in range(1, maxtries + 1):
print '\rWarning: adding jitter of {:.10e} '.format(jitter),
try:
return linalg.cholesky(A+np.eye(A.shape[0]).T*jitter, lower = True)
return linalg.cholesky(A + np.eye(A.shape[0]).T * jitter, lower=True)
except:
jitter *= 10
raise linalg.LinAlgError,"not positive definite, even with jitter."
raise linalg.LinAlgError, "not positive definite, even with jitter."
def pdinv(A, *args):
"""
@ -125,7 +118,7 @@ def pdinv(A, *args):
logdet = 2.*np.sum(np.log(np.diag(L)))
Li = chol_inv(L)
Ai, _ = linalg.lapack.flapack.dpotri(L)
#Ai = np.tril(Ai) + np.tril(Ai,-1).T
# Ai = np.tril(Ai) + np.tril(Ai,-1).T
symmetrify(Ai)
return Ai, L, Li, logdet
@ -140,7 +133,7 @@ def chol_inv(L):
"""
return linalg.lapack.flapack.dtrtri(L, lower = True)[0]
return linalg.lapack.flapack.dtrtri(L, lower=True)[0]
def multiple_pdinv(A):
@ -155,11 +148,11 @@ def multiple_pdinv(A):
hld: 0.5* the log of the determinants of A
"""
N = A.shape[-1]
chols = [jitchol(A[:,:,i]) for i in range(N)]
chols = [jitchol(A[:, :, i]) for i in range(N)]
halflogdets = [np.sum(np.log(np.diag(L[0]))) for L in chols]
invs = [linalg.lapack.flapack.dpotri(L[0],True)[0] for L in chols]
invs = [np.triu(I)+np.triu(I,1).T for I in invs]
return np.dstack(invs),np.array(halflogdets)
invs = [linalg.lapack.flapack.dpotri(L[0], True)[0] for L in chols]
invs = [np.triu(I) + np.triu(I, 1).T for I in invs]
return np.dstack(invs), np.array(halflogdets)
def PCA(Y, input_dim):
@ -179,18 +172,18 @@ def PCA(Y, input_dim):
if not np.allclose(Y.mean(axis=0), 0.0):
print "Y is not zero mean, centering it locally (GPy.util.linalg.PCA)"
#Y -= Y.mean(axis=0)
# Y -= Y.mean(axis=0)
Z = linalg.svd(Y-Y.mean(axis=0), full_matrices = False)
[X, W] = [Z[0][:,0:input_dim], np.dot(np.diag(Z[1]), Z[2]).T[:,0:input_dim]]
Z = linalg.svd(Y - Y.mean(axis=0), full_matrices=False)
[X, W] = [Z[0][:, 0:input_dim], np.dot(np.diag(Z[1]), Z[2]).T[:, 0:input_dim]]
v = X.std(axis=0)
X /= v;
W *= v;
return X, W.T
def tdot_numpy(mat,out=None):
return np.dot(mat,mat.T,out)
def tdot_numpy(mat, out=None):
return np.dot(mat, mat.T, out)
def tdot_blas(mat, out=None):
"""returns np.dot(mat, mat.T), but faster for large 2D arrays of doubles."""
@ -198,16 +191,16 @@ def tdot_blas(mat, out=None):
return np.dot(mat, mat.T)
nn = mat.shape[0]
if out is None:
out = np.zeros((nn,nn))
out = np.zeros((nn, nn))
else:
assert(out.dtype == 'float64')
assert(out.shape == (nn,nn))
assert(out.shape == (nn, nn))
# FIXME: should allow non-contiguous out, and copy output into it:
assert(8 in out.strides)
# zeroing needed because of dumb way I copy across triangular answer
out[:] = 0.0
## Call to DSYRK from BLAS
# # Call to DSYRK from BLAS
# If already in Fortran order (rare), and has the right sorts of strides I
# could avoid the copy. I also thought swapping to cblas API would allow use
# of C order. However, I tried that and had errors with large matrices:
@ -226,17 +219,17 @@ def tdot_blas(mat, out=None):
_blaslib.dsyrk_(byref(UPLO), byref(TRANS), byref(N), byref(K),
byref(ALPHA), A, byref(LDA), byref(BETA), C, byref(LDC))
symmetrify(out,upper=True)
symmetrify(out, upper=True)
return out
def tdot(*args, **kwargs):
if _blas_available:
return tdot_blas(*args,**kwargs)
return tdot_blas(*args, **kwargs)
else:
return tdot_numpy(*args,**kwargs)
return tdot_numpy(*args, **kwargs)
def DSYR_blas(A,x,alpha=1.):
def DSYR_blas(A, x, alpha=1.):
"""
Performs a symmetric rank-1 update operation:
A <- A + alpha * np.dot(x,x.T)
@ -256,9 +249,9 @@ def DSYR_blas(A,x,alpha=1.):
INCX = c_int(1)
_blaslib.dsyr_(byref(UPLO), byref(N), byref(ALPHA),
x_, byref(INCX), A_, byref(LDA))
symmetrify(A,upper=True)
symmetrify(A, upper=True)
def DSYR_numpy(A,x,alpha=1.):
def DSYR_numpy(A, x, alpha=1.):
"""
Performs a symmetric rank-1 update operation:
A <- A + alpha * np.dot(x,x.T)
@ -269,23 +262,23 @@ def DSYR_numpy(A,x,alpha=1.):
:param x: Nx1 np.array
:param alpha: scalar
"""
A += alpha*np.dot(x[:,None],x[None,:])
A += alpha * np.dot(x[:, None], x[None, :])
def DSYR(*args, **kwargs):
if _blas_available:
return DSYR_blas(*args,**kwargs)
return DSYR_blas(*args, **kwargs)
else:
return DSYR_numpy(*args,**kwargs)
return DSYR_numpy(*args, **kwargs)
def symmetrify(A,upper=False):
def symmetrify(A, upper=False):
"""
Take the square matrix A and make it symmetrical by copting elements from the lower half to the upper
works IN PLACE.
"""
N,M = A.shape
assert N==M
N, M = A.shape
assert N == M
c_contig_code = """
int iN;
for (int i=1; i<N; i++){
@ -305,13 +298,13 @@ def symmetrify(A,upper=False):
}
"""
if A.flags['C_CONTIGUOUS'] and upper:
weave.inline(f_contig_code,['A','N'], extra_compile_args=['-O3'])
weave.inline(f_contig_code, ['A', 'N'], extra_compile_args=['-O3'])
elif A.flags['C_CONTIGUOUS'] and not upper:
weave.inline(c_contig_code,['A','N'], extra_compile_args=['-O3'])
weave.inline(c_contig_code, ['A', 'N'], extra_compile_args=['-O3'])
elif A.flags['F_CONTIGUOUS'] and upper:
weave.inline(c_contig_code,['A','N'], extra_compile_args=['-O3'])
weave.inline(c_contig_code, ['A', 'N'], extra_compile_args=['-O3'])
elif A.flags['F_CONTIGUOUS'] and not upper:
weave.inline(f_contig_code,['A','N'], extra_compile_args=['-O3'])
weave.inline(f_contig_code, ['A', 'N'], extra_compile_args=['-O3'])
else:
if upper:
tmp = np.tril(A.T)
@ -319,15 +312,15 @@ def symmetrify(A,upper=False):
tmp = np.tril(A)
A[:] = 0.0
A += tmp
A += np.tril(tmp,-1).T
A += np.tril(tmp, -1).T
def symmetrify_murray(A):
A += A.T
nn = A.shape[0]
A[[range(nn),range(nn)]] /= 2.0
A[[range(nn), range(nn)]] /= 2.0
def cholupdate(L,x):
def cholupdate(L, x):
"""
update the LOWER cholesky factor of a pd matrix IN PLACE
@ -337,7 +330,7 @@ def cholupdate(L,x):
support_code = """
#include <math.h>
"""
code="""
code = """
double r,c,s;
int j,i;
for(j=0; j<N; j++){
@ -353,11 +346,11 @@ def cholupdate(L,x):
"""
x = x.copy()
N = x.size
weave.inline(code, support_code=support_code, arg_names=['N','L','x'], type_converters=weave.converters.blitz)
weave.inline(code, support_code=support_code, arg_names=['N', 'L', 'x'], type_converters=weave.converters.blitz)
def backsub_both_sides(L, X,transpose='left'):
def backsub_both_sides(L, X, transpose='left'):
""" Return L^-T * X * L^-1, assumuing X is symmetrical and L is lower cholesky"""
if transpose=='left':
if transpose == 'left':
tmp, _ = linalg.lapack.flapack.dtrtrs(L, np.asfortranarray(X), lower=1, trans=1)
return linalg.lapack.flapack.dtrtrs(L, np.asfortranarray(tmp.T), lower=1, trans=1)[0].T
else: