2012-11-29 16:39:20 +00:00
|
|
|
# Copyright (c) 2012, GPy authors (see AUTHORS.txt).
|
|
|
|
|
# Licensed under the BSD 3-clause license (see LICENSE.txt)
|
|
|
|
|
|
2013-06-05 13:02:03 +01:00
|
|
|
# tdot function courtesy of Ian Murray:
|
2013-04-26 17:26:43 +01:00
|
|
|
# Iain Murray, April 2013. iain contactable via iainmurray.net
|
|
|
|
|
# http://homepages.inf.ed.ac.uk/imurray2/code/tdot/tdot.py
|
2012-11-29 16:39:20 +00:00
|
|
|
|
2012-11-29 16:26:21 +00:00
|
|
|
import numpy as np
|
2013-06-05 13:02:03 +01:00
|
|
|
from scipy import linalg, weave
|
2012-11-29 16:26:21 +00:00
|
|
|
import types
|
2013-04-26 17:26:43 +01:00
|
|
|
import ctypes
|
|
|
|
|
from ctypes import byref, c_char, c_int, c_double # TODO
|
2013-06-05 13:02:03 +01:00
|
|
|
# import scipy.lib.lapack
|
2013-06-06 14:04:14 +01:00
|
|
|
import scipy
|
|
|
|
|
|
2013-06-06 14:51:04 +01:00
|
|
|
if np.all(np.float64((scipy.__version__).split('.')[:2]) >= np.array([0, 12])):
|
2013-06-06 14:04:14 +01:00
|
|
|
import scipy.linalg.lapack as lapack
|
|
|
|
|
else:
|
2013-06-06 14:57:51 +01:00
|
|
|
from scipy.linalg.lapack import flapack as lapack
|
2012-11-29 16:26:21 +00:00
|
|
|
|
2013-04-26 17:26:43 +01:00
|
|
|
try:
|
2013-06-05 13:02:03 +01:00
|
|
|
_blaslib = ctypes.cdll.LoadLibrary(np.core._dotblas.__file__) # @UndefinedVariable
|
2013-04-26 17:26:43 +01:00
|
|
|
_blas_available = True
|
2013-06-06 16:49:03 +01:00
|
|
|
assert hasattr('dsyrk_',_blaslib)
|
|
|
|
|
assert hasattr('dsyr_',_blaslib)
|
2013-04-26 17:26:43 +01:00
|
|
|
except:
|
|
|
|
|
_blas_available = False
|
|
|
|
|
|
2013-06-06 15:02:19 +01:00
|
|
|
def dtrtrs(A, B, lower=0, trans=0, unitdiag=0):
|
2013-09-20 13:38:20 +01:00
|
|
|
"""
|
|
|
|
|
Wrapper for lapack dtrtrs function
|
2013-06-06 14:04:14 +01:00
|
|
|
|
|
|
|
|
:param A: Matrix A
|
|
|
|
|
:param B: Matrix B
|
|
|
|
|
:param lower: is matrix lower (true) or upper (false)
|
|
|
|
|
:returns:
|
2013-09-20 13:38:20 +01:00
|
|
|
|
2013-06-06 14:04:14 +01:00
|
|
|
"""
|
2013-06-06 15:02:19 +01:00
|
|
|
return lapack.dtrtrs(A, B, lower=lower, trans=trans, unitdiag=unitdiag)
|
2013-06-06 14:04:14 +01:00
|
|
|
|
2013-06-06 15:02:19 +01:00
|
|
|
def dpotrs(A, B, lower=0):
|
2013-09-20 13:38:20 +01:00
|
|
|
"""
|
|
|
|
|
Wrapper for lapack dpotrs function
|
2013-06-06 14:04:14 +01:00
|
|
|
|
|
|
|
|
:param A: Matrix A
|
|
|
|
|
:param B: Matrix B
|
|
|
|
|
:param lower: is matrix lower (true) or upper (false)
|
|
|
|
|
:returns:
|
2013-09-20 13:38:20 +01:00
|
|
|
|
2013-06-06 14:04:14 +01:00
|
|
|
"""
|
2013-06-06 15:02:19 +01:00
|
|
|
return lapack.dpotrs(A, B, lower=lower)
|
2013-06-06 14:04:14 +01:00
|
|
|
|
2013-06-06 15:02:19 +01:00
|
|
|
def dpotri(A, lower=0):
|
2013-09-20 13:38:20 +01:00
|
|
|
"""
|
|
|
|
|
Wrapper for lapack dpotri function
|
2013-06-06 14:04:14 +01:00
|
|
|
|
|
|
|
|
:param A: Matrix A
|
|
|
|
|
:param lower: is matrix lower (true) or upper (false)
|
2013-09-17 14:27:16 +01:00
|
|
|
:returns: A inverse
|
2013-09-20 13:38:20 +01:00
|
|
|
|
2013-06-06 14:04:14 +01:00
|
|
|
"""
|
2013-06-06 15:02:19 +01:00
|
|
|
return lapack.dpotri(A, lower=lower)
|
2013-06-06 14:04:14 +01:00
|
|
|
|
2013-09-11 11:54:15 +01:00
|
|
|
def pddet(A):
|
|
|
|
|
"""
|
|
|
|
|
Determinant of a positive definite matrix, only symmetric matricies though
|
|
|
|
|
"""
|
|
|
|
|
L = jitchol(A)
|
|
|
|
|
logdetA = 2*sum(np.log(np.diag(L)))
|
|
|
|
|
return logdetA
|
|
|
|
|
|
2013-06-05 13:02:03 +01:00
|
|
|
def trace_dot(a, b):
|
2013-03-11 18:56:37 +00:00
|
|
|
"""
|
2013-09-20 13:38:20 +01:00
|
|
|
Efficiently compute the trace of the matrix product of a and b
|
2013-03-11 18:56:37 +00:00
|
|
|
"""
|
2013-06-05 13:02:03 +01:00
|
|
|
return np.sum(a * b)
|
2013-03-11 18:56:37 +00:00
|
|
|
|
2012-11-29 16:26:21 +00:00
|
|
|
def mdot(*args):
|
2013-09-20 13:38:20 +01:00
|
|
|
"""
|
|
|
|
|
Multiply all the arguments using matrix product rules.
|
2013-06-05 13:02:03 +01:00
|
|
|
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.
|
2013-09-20 13:38:20 +01:00
|
|
|
|
2013-06-05 13:02:03 +01:00
|
|
|
"""
|
|
|
|
|
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 jitchol(A, maxtries=5):
|
2013-04-10 16:50:34 +01:00
|
|
|
A = np.asfortranarray(A)
|
2013-06-06 14:04:14 +01:00
|
|
|
L, info = lapack.dpotrf(A, lower=1)
|
2013-06-05 13:02:03 +01:00
|
|
|
if info == 0:
|
2013-04-10 16:50:34 +01:00
|
|
|
return L
|
|
|
|
|
else:
|
|
|
|
|
diagA = np.diag(A)
|
2013-06-07 13:34:45 +01:00
|
|
|
if np.any(diagA <= 0.):
|
|
|
|
|
raise linalg.LinAlgError, "not pd: non-positive diagonal elements"
|
2013-06-05 13:02:03 +01:00
|
|
|
jitter = diagA.mean() * 1e-6
|
2013-06-07 13:34:45 +01:00
|
|
|
while maxtries > 0 and np.isfinite(jitter):
|
2013-05-01 15:08:55 +01:00
|
|
|
print 'Warning: adding jitter of {:.10e}'.format(jitter)
|
2013-04-10 16:50:34 +01:00
|
|
|
try:
|
2013-06-05 13:02:03 +01:00
|
|
|
return linalg.cholesky(A + np.eye(A.shape[0]).T * jitter, lower=True)
|
2013-04-10 16:50:34 +01:00
|
|
|
except:
|
|
|
|
|
jitter *= 10
|
2013-06-07 13:34:45 +01:00
|
|
|
finally:
|
|
|
|
|
maxtries -= 1
|
2013-06-05 13:02:03 +01:00
|
|
|
raise linalg.LinAlgError, "not positive definite, even with jitter."
|
2013-04-10 16:50:34 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-06-05 13:02:03 +01:00
|
|
|
def jitchol_old(A, maxtries=5):
|
2012-11-29 16:26:21 +00:00
|
|
|
"""
|
2013-09-20 17:46:23 +01:00
|
|
|
:param A: An almost pd square matrix
|
2012-11-29 16:26:21 +00:00
|
|
|
|
2012-12-06 10:16:19 -08:00
|
|
|
:rval L: the Cholesky decomposition of A
|
2012-11-29 16:26:21 +00:00
|
|
|
|
2013-09-20 13:38:20 +01:00
|
|
|
.. note:
|
|
|
|
|
|
2012-12-06 10:16:19 -08:00
|
|
|
Adds jitter to K, to enforce positive-definiteness
|
|
|
|
|
if stuff breaks, please check:
|
|
|
|
|
np.allclose(sp.linalg.cholesky(XXT, lower = True), np.triu(sp.linalg.cho_factor(XXT)[0]).T)
|
2013-09-20 13:38:20 +01:00
|
|
|
|
2012-11-29 16:26:21 +00:00
|
|
|
"""
|
|
|
|
|
try:
|
2013-06-05 13:02:03 +01:00
|
|
|
return linalg.cholesky(A, lower=True)
|
2012-11-29 16:26:21 +00:00
|
|
|
except linalg.LinAlgError:
|
|
|
|
|
diagA = np.diag(A)
|
2013-06-05 13:02:03 +01:00
|
|
|
if np.any(diagA < 0.):
|
2012-11-29 16:26:21 +00:00
|
|
|
raise linalg.LinAlgError, "not pd: negative diagonal elements"
|
2013-06-05 13:02:03 +01:00
|
|
|
jitter = diagA.mean() * 1e-6
|
|
|
|
|
for i in range(1, maxtries + 1):
|
2013-04-16 11:13:53 +01:00
|
|
|
print '\rWarning: adding jitter of {:.10e} '.format(jitter),
|
2012-11-29 16:26:21 +00:00
|
|
|
try:
|
2013-06-05 13:02:03 +01:00
|
|
|
return linalg.cholesky(A + np.eye(A.shape[0]).T * jitter, lower=True)
|
2012-11-29 16:26:21 +00:00
|
|
|
except:
|
|
|
|
|
jitter *= 10
|
|
|
|
|
|
2013-06-05 13:02:03 +01:00
|
|
|
raise linalg.LinAlgError, "not positive definite, even with jitter."
|
2012-11-29 16:26:21 +00:00
|
|
|
|
2013-04-18 16:39:55 +01:00
|
|
|
def pdinv(A, *args):
|
2012-11-29 16:26:21 +00:00
|
|
|
"""
|
2013-09-20 13:38:20 +01:00
|
|
|
|
2012-11-29 16:26:21 +00:00
|
|
|
:param A: A DxD pd numpy array
|
|
|
|
|
|
2012-12-06 09:51:13 -08:00
|
|
|
:rval Ai: the inverse of A
|
|
|
|
|
:rtype Ai: np.ndarray
|
|
|
|
|
:rval L: the Cholesky decomposition of A
|
|
|
|
|
:rtype L: np.ndarray
|
|
|
|
|
:rval Li: the Cholesky decomposition of Ai
|
|
|
|
|
:rtype Li: np.ndarray
|
|
|
|
|
:rval logdet: the log of the determinant of A
|
|
|
|
|
:rtype logdet: float64
|
2013-09-20 13:38:20 +01:00
|
|
|
|
2012-11-29 16:26:21 +00:00
|
|
|
"""
|
2013-04-18 16:39:55 +01:00
|
|
|
L = jitchol(A, *args)
|
2012-12-06 09:51:13 -08:00
|
|
|
logdet = 2.*np.sum(np.log(np.diag(L)))
|
|
|
|
|
Li = chol_inv(L)
|
2013-06-06 14:04:14 +01:00
|
|
|
Ai, _ = lapack.dpotri(L)
|
2013-06-05 13:02:03 +01:00
|
|
|
# Ai = np.tril(Ai) + np.tril(Ai,-1).T
|
2013-05-13 10:36:15 +01:00
|
|
|
symmetrify(Ai)
|
2012-11-29 16:26:21 +00:00
|
|
|
|
2012-12-06 09:51:13 -08:00
|
|
|
return Ai, L, Li, logdet
|
2012-11-29 16:26:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def chol_inv(L):
|
|
|
|
|
"""
|
|
|
|
|
Inverts a Cholesky lower triangular matrix
|
|
|
|
|
|
|
|
|
|
:param L: lower triangular matrix
|
|
|
|
|
:rtype: inverse of L
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
2013-06-06 14:04:14 +01:00
|
|
|
return lapack.dtrtri(L, lower=True)[0]
|
2012-11-29 16:26:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def multiple_pdinv(A):
|
|
|
|
|
"""
|
|
|
|
|
:param A: A DxDxN numpy array (each A[:,:,i] is pd)
|
|
|
|
|
|
2013-09-20 13:38:20 +01:00
|
|
|
:rval invs: the inverses of A
|
|
|
|
|
:rtype invs: np.ndarray
|
|
|
|
|
:rval hld: 0.5* the log of the determinants of A
|
|
|
|
|
:rtype hld: np.array
|
|
|
|
|
|
2012-11-29 16:26:21 +00:00
|
|
|
"""
|
|
|
|
|
N = A.shape[-1]
|
2013-06-05 13:02:03 +01:00
|
|
|
chols = [jitchol(A[:, :, i]) for i in range(N)]
|
2012-11-29 16:26:21 +00:00
|
|
|
halflogdets = [np.sum(np.log(np.diag(L[0]))) for L in chols]
|
2013-06-06 14:04:14 +01:00
|
|
|
invs = [lapack.dpotri(L[0], True)[0] for L in chols]
|
2013-06-05 13:02:03 +01:00
|
|
|
invs = [np.triu(I) + np.triu(I, 1).T for I in invs]
|
|
|
|
|
return np.dstack(invs), np.array(halflogdets)
|
2012-11-29 16:26:21 +00:00
|
|
|
|
|
|
|
|
|
2013-06-05 11:17:15 +01:00
|
|
|
def PCA(Y, input_dim):
|
2012-11-29 16:26:21 +00:00
|
|
|
"""
|
|
|
|
|
Principal component analysis: maximum likelihood solution by SVD
|
|
|
|
|
|
|
|
|
|
:param Y: NxD np.array of data
|
2013-06-05 11:17:15 +01:00
|
|
|
:param input_dim: int, dimension of projection
|
2012-11-29 16:26:21 +00:00
|
|
|
|
2013-09-20 13:38:20 +01:00
|
|
|
|
2013-06-05 11:17:15 +01:00
|
|
|
:rval X: - Nxinput_dim np.array of dimensionality reduced data
|
2013-09-20 13:38:20 +01:00
|
|
|
:rval W: - input_dimxD mapping from X to Y
|
|
|
|
|
|
2012-11-29 16:26:21 +00:00
|
|
|
"""
|
|
|
|
|
if not np.allclose(Y.mean(axis=0), 0.0):
|
|
|
|
|
print "Y is not zero mean, centering it locally (GPy.util.linalg.PCA)"
|
2013-05-08 20:30:36 +01:00
|
|
|
|
2013-06-05 13:02:03 +01:00
|
|
|
# Y -= Y.mean(axis=0)
|
2012-11-29 16:26:21 +00:00
|
|
|
|
2013-06-05 13:02:03 +01:00
|
|
|
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]]
|
2012-11-29 16:26:21 +00:00
|
|
|
v = X.std(axis=0)
|
|
|
|
|
X /= v;
|
|
|
|
|
W *= v;
|
|
|
|
|
return X, W.T
|
2013-04-26 17:26:43 +01:00
|
|
|
|
|
|
|
|
|
2013-06-05 13:02:03 +01:00
|
|
|
def tdot_numpy(mat, out=None):
|
|
|
|
|
return np.dot(mat, mat.T, out)
|
2013-04-26 17:26:43 +01:00
|
|
|
|
|
|
|
|
def tdot_blas(mat, out=None):
|
|
|
|
|
"""returns np.dot(mat, mat.T), but faster for large 2D arrays of doubles."""
|
|
|
|
|
if (mat.dtype != 'float64') or (len(mat.shape) != 2):
|
|
|
|
|
return np.dot(mat, mat.T)
|
|
|
|
|
nn = mat.shape[0]
|
2013-04-26 19:32:33 +01:00
|
|
|
if out is None:
|
2013-06-05 13:02:03 +01:00
|
|
|
out = np.zeros((nn, nn))
|
2013-04-26 17:26:43 +01:00
|
|
|
else:
|
|
|
|
|
assert(out.dtype == 'float64')
|
2013-06-05 13:02:03 +01:00
|
|
|
assert(out.shape == (nn, nn))
|
2013-04-26 17:26:43 +01:00
|
|
|
# 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
|
|
|
|
|
|
2013-06-05 13:02:03 +01:00
|
|
|
# # Call to DSYRK from BLAS
|
2013-04-26 17:26:43 +01:00
|
|
|
# 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:
|
|
|
|
|
# http://homepages.inf.ed.ac.uk/imurray2/code/tdot/tdot_broken.py
|
2013-04-26 19:32:33 +01:00
|
|
|
mat = np.asfortranarray(mat)
|
2013-04-26 17:26:43 +01:00
|
|
|
TRANS = c_char('n')
|
|
|
|
|
N = c_int(mat.shape[0])
|
|
|
|
|
K = c_int(mat.shape[1])
|
|
|
|
|
LDA = c_int(mat.shape[0])
|
|
|
|
|
UPLO = c_char('l')
|
|
|
|
|
ALPHA = c_double(1.0)
|
|
|
|
|
A = mat.ctypes.data_as(ctypes.c_void_p)
|
|
|
|
|
BETA = c_double(0.0)
|
|
|
|
|
C = out.ctypes.data_as(ctypes.c_void_p)
|
|
|
|
|
LDC = c_int(np.max(out.strides) / 8)
|
|
|
|
|
_blaslib.dsyrk_(byref(UPLO), byref(TRANS), byref(N), byref(K),
|
|
|
|
|
byref(ALPHA), A, byref(LDA), byref(BETA), C, byref(LDC))
|
|
|
|
|
|
2013-06-05 13:02:03 +01:00
|
|
|
symmetrify(out, upper=True)
|
2013-04-26 17:26:43 +01:00
|
|
|
|
|
|
|
|
return out
|
|
|
|
|
|
|
|
|
|
def tdot(*args, **kwargs):
|
|
|
|
|
if _blas_available:
|
2013-06-05 13:02:03 +01:00
|
|
|
return tdot_blas(*args, **kwargs)
|
2013-04-26 17:26:43 +01:00
|
|
|
else:
|
2013-06-05 13:02:03 +01:00
|
|
|
return tdot_numpy(*args, **kwargs)
|
2013-04-26 17:26:43 +01:00
|
|
|
|
2013-06-05 13:02:03 +01:00
|
|
|
def DSYR_blas(A, x, alpha=1.):
|
2013-05-15 16:25:40 +01:00
|
|
|
"""
|
|
|
|
|
Performs a symmetric rank-1 update operation:
|
|
|
|
|
A <- A + alpha * np.dot(x,x.T)
|
|
|
|
|
|
|
|
|
|
:param A: Symmetric NxN np.array
|
|
|
|
|
:param x: Nx1 np.array
|
|
|
|
|
:param alpha: scalar
|
2013-09-20 13:38:20 +01:00
|
|
|
|
2013-05-15 16:25:40 +01:00
|
|
|
"""
|
2013-05-13 12:54:55 +01:00
|
|
|
N = c_int(A.shape[0])
|
|
|
|
|
LDA = c_int(A.shape[0])
|
|
|
|
|
UPLO = c_char('l')
|
|
|
|
|
ALPHA = c_double(alpha)
|
|
|
|
|
A_ = A.ctypes.data_as(ctypes.c_void_p)
|
|
|
|
|
x_ = x.ctypes.data_as(ctypes.c_void_p)
|
|
|
|
|
INCX = c_int(1)
|
|
|
|
|
_blaslib.dsyr_(byref(UPLO), byref(N), byref(ALPHA),
|
|
|
|
|
x_, byref(INCX), A_, byref(LDA))
|
2013-06-05 13:02:03 +01:00
|
|
|
symmetrify(A, upper=True)
|
2013-05-13 12:54:55 +01:00
|
|
|
|
2013-06-05 13:02:03 +01:00
|
|
|
def DSYR_numpy(A, x, alpha=1.):
|
2013-05-19 19:16:25 +01:00
|
|
|
"""
|
|
|
|
|
Performs a symmetric rank-1 update operation:
|
|
|
|
|
A <- A + alpha * np.dot(x,x.T)
|
|
|
|
|
|
|
|
|
|
:param A: Symmetric NxN np.array
|
|
|
|
|
:param x: Nx1 np.array
|
|
|
|
|
:param alpha: scalar
|
2013-09-20 13:38:20 +01:00
|
|
|
|
2013-05-19 19:16:25 +01:00
|
|
|
"""
|
2013-06-05 13:02:03 +01:00
|
|
|
A += alpha * np.dot(x[:, None], x[None, :])
|
2013-05-19 19:16:25 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def DSYR(*args, **kwargs):
|
|
|
|
|
if _blas_available:
|
2013-06-05 13:02:03 +01:00
|
|
|
return DSYR_blas(*args, **kwargs)
|
2013-05-19 19:16:25 +01:00
|
|
|
else:
|
2013-06-05 13:02:03 +01:00
|
|
|
return DSYR_numpy(*args, **kwargs)
|
2013-05-19 19:16:25 +01:00
|
|
|
|
2013-06-05 13:02:03 +01:00
|
|
|
def symmetrify(A, upper=False):
|
2013-04-26 17:26:43 +01:00
|
|
|
"""
|
|
|
|
|
Take the square matrix A and make it symmetrical by copting elements from the lower half to the upper
|
|
|
|
|
|
|
|
|
|
works IN PLACE.
|
|
|
|
|
"""
|
2013-06-05 13:02:03 +01:00
|
|
|
N, M = A.shape
|
|
|
|
|
assert N == M
|
2013-10-11 16:19:27 -07:00
|
|
|
|
2013-04-26 17:26:43 +01:00
|
|
|
c_contig_code = """
|
2013-05-13 17:23:49 +01:00
|
|
|
int iN;
|
2013-04-26 17:26:43 +01:00
|
|
|
for (int i=1; i<N; i++){
|
2013-05-13 17:23:49 +01:00
|
|
|
iN = i*N;
|
2013-04-26 17:26:43 +01:00
|
|
|
for (int j=0; j<i; j++){
|
2013-05-13 17:23:49 +01:00
|
|
|
A[i+j*N] = A[iN+j];
|
2013-04-26 17:26:43 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
"""
|
|
|
|
|
f_contig_code = """
|
2013-05-13 17:23:49 +01:00
|
|
|
int iN;
|
2013-04-26 17:26:43 +01:00
|
|
|
for (int i=1; i<N; i++){
|
2013-05-13 17:23:49 +01:00
|
|
|
iN = i*N;
|
2013-04-26 17:26:43 +01:00
|
|
|
for (int j=0; j<i; j++){
|
2013-05-13 17:23:49 +01:00
|
|
|
A[iN+j] = A[i+j*N];
|
2013-04-26 17:26:43 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
"""
|
2013-10-11 16:19:27 -07:00
|
|
|
|
|
|
|
|
N = int(N) # for safe type casting
|
2013-04-26 19:32:33 +01:00
|
|
|
if A.flags['C_CONTIGUOUS'] and upper:
|
2013-06-05 13:02:03 +01:00
|
|
|
weave.inline(f_contig_code, ['A', 'N'], extra_compile_args=['-O3'])
|
2013-04-26 19:32:33 +01:00
|
|
|
elif A.flags['C_CONTIGUOUS'] and not upper:
|
2013-06-05 13:02:03 +01:00
|
|
|
weave.inline(c_contig_code, ['A', 'N'], extra_compile_args=['-O3'])
|
2013-04-26 19:32:33 +01:00
|
|
|
elif A.flags['F_CONTIGUOUS'] and upper:
|
2013-06-05 13:02:03 +01:00
|
|
|
weave.inline(c_contig_code, ['A', 'N'], extra_compile_args=['-O3'])
|
2013-04-26 19:32:33 +01:00
|
|
|
elif A.flags['F_CONTIGUOUS'] and not upper:
|
2013-06-05 13:02:03 +01:00
|
|
|
weave.inline(f_contig_code, ['A', 'N'], extra_compile_args=['-O3'])
|
2013-04-26 17:26:43 +01:00
|
|
|
else:
|
2013-05-28 15:50:18 +01:00
|
|
|
if upper:
|
|
|
|
|
tmp = np.tril(A.T)
|
|
|
|
|
else:
|
|
|
|
|
tmp = np.tril(A)
|
2013-04-26 17:26:43 +01:00
|
|
|
A[:] = 0.0
|
|
|
|
|
A += tmp
|
2013-06-05 13:02:03 +01:00
|
|
|
A += np.tril(tmp, -1).T
|
2013-04-26 17:26:43 +01:00
|
|
|
|
2013-05-13 12:54:55 +01:00
|
|
|
|
2013-04-26 17:26:43 +01:00
|
|
|
def symmetrify_murray(A):
|
|
|
|
|
A += A.T
|
|
|
|
|
nn = A.shape[0]
|
2013-06-05 13:02:03 +01:00
|
|
|
A[[range(nn), range(nn)]] /= 2.0
|
2013-04-26 17:26:43 +01:00
|
|
|
|
2013-06-05 13:02:03 +01:00
|
|
|
def cholupdate(L, x):
|
2013-05-03 14:00:22 +01:00
|
|
|
"""
|
|
|
|
|
update the LOWER cholesky factor of a pd matrix IN PLACE
|
|
|
|
|
|
2013-09-20 13:38:20 +01:00
|
|
|
if L is the lower chol. of K, then this function computes L\_
|
|
|
|
|
where L\_ is the lower chol of K + x*x^T
|
|
|
|
|
|
2013-05-03 14:00:22 +01:00
|
|
|
"""
|
|
|
|
|
support_code = """
|
|
|
|
|
#include <math.h>
|
|
|
|
|
"""
|
2013-06-05 13:02:03 +01:00
|
|
|
code = """
|
2013-05-03 14:00:22 +01:00
|
|
|
double r,c,s;
|
|
|
|
|
int j,i;
|
|
|
|
|
for(j=0; j<N; j++){
|
|
|
|
|
r = sqrt(L(j,j)*L(j,j) + x(j)*x(j));
|
|
|
|
|
c = r / L(j,j);
|
|
|
|
|
s = x(j) / L(j,j);
|
|
|
|
|
L(j,j) = r;
|
|
|
|
|
for (i=j+1; i<N; i++){
|
|
|
|
|
L(i,j) = (L(i,j) + s*x(i))/c;
|
|
|
|
|
x(i) = c*x(i) - s*L(i,j);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
"""
|
|
|
|
|
x = x.copy()
|
|
|
|
|
N = x.size
|
2013-06-05 13:02:03 +01:00
|
|
|
weave.inline(code, support_code=support_code, arg_names=['N', 'L', 'x'], type_converters=weave.converters.blitz)
|
2013-05-13 17:04:59 +01:00
|
|
|
|
2013-06-05 13:02:03 +01:00
|
|
|
def backsub_both_sides(L, X, transpose='left'):
|
2013-05-13 17:04:59 +01:00
|
|
|
""" Return L^-T * X * L^-1, assumuing X is symmetrical and L is lower cholesky"""
|
2013-06-05 13:02:03 +01:00
|
|
|
if transpose == 'left':
|
2013-06-06 14:04:14 +01:00
|
|
|
tmp, _ = lapack.dtrtrs(L, np.asfortranarray(X), lower=1, trans=1)
|
|
|
|
|
return lapack.dtrtrs(L, np.asfortranarray(tmp.T), lower=1, trans=1)[0].T
|
2013-05-14 11:20:44 +01:00
|
|
|
else:
|
2013-06-06 14:04:14 +01:00
|
|
|
tmp, _ = lapack.dtrtrs(L, np.asfortranarray(X), lower=1, trans=0)
|
|
|
|
|
return lapack.dtrtrs(L, np.asfortranarray(tmp.T), lower=1, trans=0)[0].T
|