Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dense Cholesky update in Python

Could anyone point me to a library/code allowing me to perform low-rank updates on a Cholesky decomposition in python (numpy)? Matlab offers this functionality as a function called 'cholupdate'. LINPACK also has this functionality, but it has (to my knowledge) not yet been ported to LAPACK and hence isn't available in e.g. scipy.

I found out that scikits.sparse offers a similar function based on CHOLMOD, but my matrices are dense.

Is there any code available for python with 'cholupdate''s functionality that's compatible with numpy?

Thanks!

like image 510
user1116403 Avatar asked Dec 26 '11 14:12

user1116403


3 Answers

Here is a Python package that does rank 1 updates and downdates on Cholesky factors using Cython: https://github.com/jcrudy/choldate

Example:

from choldate import cholupdate, choldowndate
import numpy

#Create a random positive definite matrix, V
numpy.random.seed(1)
X = numpy.random.normal(size=(100,10))
V = numpy.dot(X.transpose(),X)

#Calculate the upper Cholesky factor, R
R = numpy.linalg.cholesky(V).transpose()

#Create a random update vector, u
u = numpy.random.normal(size=R.shape[0])

#Calculate the updated positive definite matrix, V1, and its Cholesky factor, R1
V1 = V + numpy.outer(u,u)
R1 = numpy.linalg.cholesky(V1).transpose()

#The following is equivalent to the above
R1_ = R.copy()
cholupdate(R1_,u.copy())
assert(numpy.all((R1 - R1_)**2 < 1e-16))

#And downdating is the inverse of updating
R_ = R1.copy()
choldowndate(R_,u.copy())
assert(numpy.all((R - R_)**2 < 1e-16))
like image 79
jcrudy Avatar answered Sep 23 '22 19:09

jcrudy


This should do a rank-1 update or downdate on numpy arrays R and x with sign '+' or '-' corresponding to update or downdate. (Ported from MATLAB cholupdate at the Wikipedia page: http://en.wikipedia.org/wiki/Cholesky_decomposition):

def cholupdate(R,x,sign):
    import numpy as np
      p = np.size(x)
      x = x.T
      for k in range(p):
        if sign == '+':
          r = np.sqrt(R[k,k]**2 + x[k]**2)
        elif sign == '-':
          r = np.sqrt(R[k,k]**2 - x[k]**2)
        c = r/R[k,k]
        s = x[k]/R[k,k]
        R[k,k] = r
        if sign == '+':
          R[k,k+1:p] = (R[k,k+1:p] + s*x[k+1:p])/c
        elif sign == '-':
          R[k,k+1:p] = (R[k,k+1:p] - s*x[k+1:p])/c
        x[k+1:p]= c*x[k+1:p] - s*R[k, k+1:p]
      return R
like image 40
Andrew Avatar answered Sep 19 '22 19:09

Andrew


This guy is doing something similar using scikits and numpy/scipy.

like image 32
Benjamin Avatar answered Sep 23 '22 19:09

Benjamin