简体   繁体   English

使用LU分解求逆矩阵

[英]Inverting a matrix using the LU decomposition

I have written the following Matrix class in cython for the matrix inversion and some other linear algebra operations. 我在cython中编写了以下Matrix class ,用于矩阵求逆和其他一些线性代数运算。 I tried to use the LU decomposition , in order to compute the inverse of a matrix. 我尝试使用LU分解来计算矩阵的逆。 The speed of code is good. 代码的速度很好。 I tried to implement this code in cython . 我试图在cython实现此代码 I have checked every line of my code and compared with the given code couple of times but I still return wrong answer. 我已经检查了我的代码的每一行,并与给定的代码进行了几次比较,但是我仍然返回错误的答案。

matrix.pyx 矩阵.pyx

from libcpp.vector cimport vector
import cython
cimport cython  
import numpy as np
cimport numpy as np
import ctypes                                             
from libc.math cimport log, exp, pow, fabs                                              
from libc.stdint cimport *
from libcpp.string cimport string
from libc.stdio cimport *
from libcpp cimport bool
cdef extern from "<iterator>" namespace "std" nogil:
    cdef cppclass iterator[Category, T, Distance, Pointer, Reference]:
        pass
    cdef cppclass output_iterator_tag:
        pass
    cdef cppclass input_iterator_tag:
        pass
    cdef cppclass forward_iterator_tag(input_iterator_tag):
        pass

cdef extern from "<algorithm>" namespace "std" nogil:       
   void fill [ForwardIterator, T](ForwardIterator, ForwardIterator, T& )

cdef class Matrix:    
     def __cinit__(self, size_t rows=0, size_t columns=0, bint Identity=False, bint ones=False):
         self._rows=rows
         self._columns=columns
         self.matrix=new vector[double]()
         self.matrix.resize(rows*columns)

         if Identity:
            self._IdentityMatrix()

         if ones:
            self._fillWithOnes()

     def __dealloc__(self):
         del self.matrix

     property rows:
        def __get__(self):
            return self._rows
        def __set__(self, size_t x):
            self._rows = x    
     property columns:
        def __get__(self):
            return self._columns
        def __set__(self, size_t y):
            self._columns = y    

     cpdef double getVal(self, size_t r, size_t c):
           return self.matrix[0][r*self._columns+c]

     cpdef void setVal(self, size_t r, size_t c, double v): 
           self.matrix[0][r*self._columns+c] = v

     @cython.boundscheck(False)
     @cython.wraparound(False)
     cdef void _fillWithOnes(self):
          fill(self.matrix.begin(),self.matrix.end(),1.)

     cdef void _IdentityMatrix(self):
          cdef size_t i 
          if (self._rows!=self._columns):
             raise Exception('In order to generate identity matrix, the number of rows and columns must be equal')
          else:
             for i from 0 <= i <self._columns:
                 self.setVal(i,i,1.0)

     @cython.boundscheck(False)
     @cython.wraparound(False)
     cpdef Matrix Inv(self):               
           cdef Matrix A_inverse = Matrix(self._rows,self._columns)
           cdef MatrixList LU = ludcmp(self)
           cdef Matrix A    = LU.get(0)
           cdef Matrix indx = LU.get(1)
           cdef Matrix d    = LU.get(2)
           cdef double det  = d.getVal(0,0)
           cdef int i, j
           cdef np.ndarray[np.float64_t, ndim=2] L   = np.zeros((self._rows,self._columns),dtype=np.float64)
           cdef np.ndarray[np.float64_t, ndim=2] U   = np.zeros((self._rows,self._columns),dtype=np.float64)
           cdef Matrix col = Matrix(self._rows,1)
           for i from 0 <= i < self._rows: 
               for j from 0 <= j < self._columns:  
                   if (j>i):
                       U[i,j]=A.getVal(i,j)
                       L[i,j]=0
                   elif (j<i):
                       U[i,j]=0
                       L[i,j]=A.getVal(i,j)
                   else:
                      U[i,j]=A.getVal(i,j)
                      L[i,j]=1
           print "product of a lower triangular matrix L and an upper triangular matrix U:", np.dot(L, U)
           for i from 0 <= i < self._rows: 
               det*= A.getVal(i,i)
               for j from 0 <= j < self._columns:
                   if (i==j):
                      col.setVal(j,0,1)
               col=lubksb(A, indx, col)     
               for j from 0 <= j < self._columns:
                   A_inverse.setVal(j,i,col.getVal(j,0))
           print "determinant of matrix %.4f"%(det)
           return A_inverse

cdef class MatrixList:
     def __cinit__(self):
         self.inner = []

     cdef void append(self, Matrix a):
          self.inner.append(a)

     cdef Matrix get(self, int i):
          return <Matrix> self.inner[i]

     def __len__(self):
         return len(self.inner)


@cython.boundscheck(False)
@cython.wraparound(False)    
cdef Matrix lubksb(Matrix a, Matrix indx, Matrix b):
     cdef int n = a.rows
     cdef int i, ip, j
     cdef int ii = 0
     cdef double su
     for i from 0 <= i < n: 
         ip = <int>indx.getVal(i,0)
         su = b.getVal(ip,0)
         b.setVal(ip,0, b.getVal(i,0))
         if (ii):
             for j from ii <= j < (i-1): 
                 su -= a.getVal(i,j) * b.getVal(j,0)
         elif (su):
            ii = i       
         b.setVal(i, 0, su)
     for i from n > i >= 0: 
         su = b.getVal(i,0)
         for j from (i+1) <= j < n:
             su -= a.getVal(i,j) * b.getVal(j,0)
         b.setVal(i, 0, su/a.getVal(i,i))
     return b

@cython.boundscheck(False)
@cython.wraparound(False)    
cdef MatrixList ludcmp(Matrix a):
     #Given a matrix a_{nxn}, this routine replaces it by the LU decomposition of a row-wise permutation of itself.
     cdef MatrixList LU = MatrixList()
     cdef int n = a.rows
     cdef int i, j, k, imax
     cdef double big, dum, su, temp
     cdef Matrix vv   = Matrix(n,1)
     cdef Matrix indx = Matrix(n,1) #an output vector that records the row permutation effected by the partial pivoting
     cdef Matrix d    = Matrix(1,1, ones= True)  #an output as +1 or -1 depending on whether the number of row interchanges was even or odd, respectively
     cdef double TINY = 1.1e-16
     for i from 0 <= i < n: 
         big = 0.0
         for j from 0 <= j < n:
             temp=fabs(a.getVal(i,j))
             if (temp > big):
                big=temp
         if (big ==0.0):
             raise Exception("ERROR! ludcmp: Singular matrix\n")
         vv.setVal(i,0,1.0/big)

     for j from 0 <= j < n:
         for i from 0 <= i < j: 
             su = a.getVal(i,j)
             for k from 0 <= k < i:
                 su -= a.getVal(i,k)*a.getVal(k,j)
             a.setVal(i,j,su)

         big=0.0
         for i from j<= i< n:
             su = a.getVal(i,j)
             for k from 0 <= k < j:
                 su -= a.getVal(i,k)*a.getVal(k,j)
             a.setVal(i, j, su)
             dum=vv.getVal(i,0)*fabs(su )
             if (dum >= big):
                big=dum
                imax=i

         if (j != imax):
            for k from 0 <= k < n:
                dum = a.getVal(imax,k)
                a.setVal(imax, k, a.getVal(j,k))
                a.setVal(j,k, dum)
            d.setVal(0, 0, -d.getVal(0,0))
            vv.setVal(imax, 0, vv.getVal(j, 0))
         indx.setVal(j, 0, imax)
         if (a.getVal(j,j) == 0.0):
             a.setVal(j,j, TINY)
         if (j != (n-1)):
            dum=1.0/a.getVal(j,j)
            for i from (j+1)<= i <n:
                a.setVal(i,j, a.getVal(i,j)*dum)
     LU.append(<Matrix>a)
     LU.append(<Matrix>indx)
     LU.append(<Matrix>d)
     return LU

matrix.pxd matrix.pxd

from libcpp.vector cimport vector
cdef class MatrixList:
     cdef list inner
     cdef void append(self, Matrix a)
     cdef Matrix get(self, int i)

cdef class Matrix:
     cdef vector[double] *matrix   
     cdef size_t _rows
     cdef size_t _columns
     cdef bint Identity
     cdef bint ones

     cpdef double getVal(self, size_t r, size_t c)
     cpdef void setVal(self, size_t r, size_t c, double v)
     cpdef Matrix transpose(self)
     cdef void _IdentityMatrix(self)
     cdef void _fillWithOnes(self)
     cpdef Matrix Inv(self)         
cdef Matrix lubksb(Matrix a, Matrix indx, Matrix b)    
cdef MatrixList ludcmp(Matrix a)

Any help to find the bug will be appreciated. 查找错误的任何帮助将不胜感激。

example: 例:

import numpy
from matrix import Matrix
from numpy.linalg import inv
import timeit
import numpy as np
r=numpy.random.random((100, 100))
d=Matrix(r.shape[0],r.shape[1])
for i in range(d.rows):
     for j in range(d.columns):
         d.setVal(i,j,r[i,j])        


start = timeit.default_timer()
x=d.Inv()
stop = timeit.default_timer()
print "LU decomposition:", stop - start 

I figured out that there are very small mistakes I made in the lubksb function and by fixing them I am getting the right answer. 我发现在lubksb函数中犯了很小的错误,通过修复它们,我得到了正确的答案。 Here is the fixed code: 这是固定代码:

@cython.boundscheck(False)
@cython.wraparound(False)    
cdef Matrix lubksb(Matrix a, Matrix indx, Matrix b):
     cdef int n = a.rows
     cdef int i, ip, j
     cdef int ii = 0
     cdef double su
     for i from 0 <= i < n: 
         ip = <int>indx.getVal(i,0)
         su = b.getVal(ip,0)
         b.setVal(ip,0, b.getVal(i,0))
         if (ii>=0):
             for j from ii <= j <= (i-1): 
                 su -= a.getVal(i,j) * b.getVal(j,0)
         elif (su):
            ii = i       
         b.setVal(i, 0, su)
     for i from n >= i >= 0: 
         su = b.getVal(i,0)
         for j from (i+1) <= j < n:
             su -= a.getVal(i,j) * b.getVal(j,0)
         if (a.getVal(i,i)==0.0):
             a.setVal(i,i, 1.1e-16)
         b.setVal(i, 0, su/a.getVal(i,i))
     return b

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM