The linear algebra module (best.linalg) defines several functions that cannot be found in numpy or scipy but are extremely useful in various Bayesian problems.
Being able to avoid forming the Kronecker products in linear algebra can save lots of memory and time. Here are a few functions that we have put together. They should be slef-explanatory.
Multiply a Kronecker product of matrices with a vector.
where are suitable matrices. The characteristic of the routine is that it does not form the Kronecker product explicitly. Also, can be a matrix of appropriate dimensions. Of course, it will throw an exception if you don’t have the dimensions right.
Parameters: |
|
---|---|
Returns: | The product. |
Return type: | A 2D numpy array. If x was 1D, then it represents a columntmatrix (i.e., a vector). |
Here is an example:
>>> import numpy as np
>>> import best.linalg
>>> A1 = np.array([[2, -1, 0], [-1, 2, -1], [0, -1, 2]])
>>> A2 = A1
>>> A = (A1, A2)
>>> x = np.random.randn(A1.shape[1] * A2.shape[1])
>>> y = best.linalg.kron_prod(A, x)
You should compare the result with:
>>> ...
>>> z = np.dot(np.kron(A1, A2), x)
The last ones forms the Kronecker product explicitly and uses much more memory.
Solve a linear system involving Kronecker products.
where are suitable matrices and is a vector or a matrix.
Parameters: |
|
---|---|
Returns: | The solution of the linear system. |
Return type: | A numpy array of the same type as y. |
Here is an example:
>>> import numpy as np
>>> import best.linalg
>>> A1 = np.array([[2, -1, 0], [-1, 2, -1], [0, -1, 2]])
>>> A2 = A1
>>> A = (A1, A2)
>>> y = np.random.randn(A1.shape[1] * A2.shape[1])
>>> x = best.linalg.kron_solve(A, y)
Compare this with:
>>> z = np.linalg.solve(np.kron(A1, A2), y)
which actually builds the Kronecker product.
Updates the Cholesky decomposition of a matrix.
We assume that is the lower Cholesky decomposition of an matrix , and we want to calculate the Cholesky decomposition of the matrix:
It can be easily shown that the Cholesky decomposition of is given by:
where
and
Parameters: |
|
---|---|
Returns: | The lower Cholesky decomposition of the new matrix. |
Return type: | 2D numpy array |
Here is an example:
>>> import numpy as np
>>> import best.linalg
>>> A = np.array([[2, -1, 0], [-1, 2, -1], [0, -1, 2]])
>>> A_new = np.array([[2, -1, 0, 0], [-1, 2, -1, 0], [0, -1, 2, -1],\
... [0, 0, -1, 2]])
>>> L = np.linalg.cholesky(A)
>>> B = A_new[:3, 3:]
>>> C = A_new[3:, 3:]
>>> L_new = best.linalg.update_cholesky(L, B, C)
to be compared with:
>>> L_new = np.linalg.cholesky(A_new)
Update the solution of Cholesky-solved linear system.
Assume that originally we had an lower triangular matrix and that we have already solved the linear system:
Now, we wish to solve the linear system:
where is again lower triangular matrix whose top component is identical to and is . The solution is:
where is the solution of the triangular system:
where is the lower component of and is the bottom left component of .
Parameters: |
|
---|---|
Returns: | The solution of the linear system. |
Return type: | numpy array of the same type as x |
Here is an example:
>>> A = np.array([[2, -1, 0], [-1, 2, -1], [0, -1, 2]])
>>> A_new = np.array([[2, -1, 0, 0], [-1, 2, -1, 0], [0, -1, 2, -1],
... [0, 0, -1, 2]])
>>> L = np.linalg.cholesky(A)
>>> B = A_new[:3, 3:]
>>> C = A_new[3:, 3:]
>>> L_new = best.linalg.update_cholesky(L, B, C)
>>> L_new_real = np.linalg.cholesky(A_new)
>>> y = np.random.randn(3)
>>> x = np.linalg.solve(L, y)
>>> z = np.random.randn(1)
>>> x_new = best.linalg.update_cholesky_linear_system(x, L_new, z)
and compare it with:
>>> x_new_real = np.linalg.solve(L_new_real, np.hstack([y, z]))
Let and . The Generalized Singular Value Decomposition of is such that
where and are orthogonal matrices and is the transpose of . Let be the effective numerical rank of the matrix , then is a non-singular upper triangular matrix, and are and “diagonal” matrices. The particular structures of and depend on the sign of . Consult the theory for more details. This decomposition is extremely useful in computing the statistics required for best.rvm.RelevantVectorMachine. Here is a class that interfaces LAPACK’s dggsvd:
Inherits : | best.Object |
---|
A class that represents the generalized svd decomposition of A and B.
Initialize the object and perform the decomposition.
A copy of A and B will be made.
Parameters: |
|
---|
Warning
Do not use the functionality that skips the computation of U, V or Q. It does not work at the moment.
Get the final form of the copy of A.
Get the final form of the copy of B.
Get the vector of singular values of A.
Get the vector of singular values of B.
Get the orthogonal matrix .
Get the orthogonal matrix .
Get the orthogonal matrix .
Get the number of rows of .
Get the number of columns of .
Get the number of rows of .
Get .
Get .
Get the non-singular, upper triangular matrix .
Get the diagonal matrix. See doc of dggsvd.
Get the diagonal matrix. See doc of ggsvd.
Get the “diagonal” matrix.
Get the “diagonal” matrix.
Let be a positive semi-definite matrix. The class best.linalg.IncompleteCholesky computes the Cholesky factorization with complete pivoting of .
The factorization has the form:
(1)
or
(2)
where is an upper triangular matrix, is a lower triangular matrix, is a permutation matrix and is the (numerical) rank of matrix .
Inherits : | best.Object |
---|
An interface to the LAPACK Fortran routine ?pstrf which performs an Cholesky factorization with complete pivoting of a real symmetric positive semidefinite matrix A.
Initialize the object.
Parameters: |
|
---|
Get the matrix A.
Get the lower Cholesky factor (Returns None if not computed).
Get the upper Cholesky factor (Returns None if not computed).
Get the numerical rank of A.
Get a vector representing the permutation matrix P.
Get the permutation matrix P.
Here is an example of how the class can be used:
import numpy as np
from best.maps import CovarianceFunctionSE
from best.linalg import IncompleteCholesky
x = np.linspace(-5, 5, 10)
f = CovarianceFunctionSE(1)
A = f(x, x, hyp=10.)
#np.linalg.cholesky # This will fail to compute the normal
# Cholesky decomposition.
ic = IncompleteCholesky(A)
print 'rank: ', ic.rank
print 'piv: ', ic.piv
LL = np.dot(ic.L, ic.L.T)
print np.linalg.norm((LL - np.dot(ic.P.T, np.dot(A, ic.P))))
This should produce the following text:
rank: 9
piv: [0 9 4 7 2 8 1 5 6 3]
3.33066907388e-16