Matrix Operations -- Transpose +Determinant + Adjugate+ Inverse + Gram-Schimidt +LUP + QR + Eigen

Matrix Operations


这些函数操作的实现里面,我没有用一个Class抽象矩阵之后,再做操作实现.

关键还是希望减少阅读"困难".

如果你看到这篇笔记贴,希望不管感兴趣哪种操作实现,都可以很快的从Python内置数据结构入手,不用关心抽象.把注意力都集中在算法实现上面.


目前很多只是算法实现,还有时间复杂度高的值得优化的地方..

但是能用...


特比特别注意,这里有些函数实现的时候,我调用了,transpose这个转置的实现.

因为数学领域里面,总是喜欢用列向量 column vector,然后实际上Python实现的时候是很不方面对列向量做计算的.于是我有时候会使用转置,使之变成行向量,来进行计算会方便的多.




当你遇到坑爹又装逼的矩阵运算的表怕,一切都是纸老虎!


目前实现的主要矩阵操作:

 Transpose +Determinant + Adjugate+ Inverse + Gram-Schimidt +LUP decomnposition + QR decomposition



Determinant : 行列式求值


Matrix Operations -- Transpose +Determinant + Adjugate+ Inverse + Gram-Schimidt +LUP + QR + Eigen_第1张图片

对于行列式求值,我实现了一个函数determinant(),用来求给定行列式的.

    def determinant(self, matrix) :
        row = len(matrix)
        col = len(matrix[0])

        if row == 1 :
            return matrix
        elif row == 2 :
            return matrix[0][0]*matrix[1][1] - matrix[1][0] * matrix[0][1]

        ret_val = 0
        for i in range(0, col) :
            tmp_mat = [[0 for x in range(0, col-1)] for y in range(0, row-1)]

            for m in range(0, row-1) :
                n = 0
                while n < col-1 :
                    if n < i :
                        tmp_mat[m][n] = matrix[m+1][n]
                    else :
                        tmp_mat[m][n] = matrix[m+1][n+1] 
                    n += 1

            ret_val += ((-1)**(i)) * matrix[0][i] * \
                       self.determinant(tmp_mat)

        return ret_val

Python 的numpy模块有内嵌的行列式求值函数det()

Matrix Operations -- Transpose +Determinant + Adjugate+ Inverse + Gram-Schimidt +LUP + QR + Eigen_第2张图片




Dot Product:点积

骚年啊!醒醒啊!你肿么可以把点积和内积弄混!!!

Matrix Operations -- Transpose +Determinant + Adjugate+ Inverse + Gram-Schimidt +LUP + QR + Eigen_第3张图片



The Gram-Schimidt Process : 正交化


这里有一篇关于讨论Gram-Schimidt的文章,我觉得蛮好的:

http://cavern.uark.edu/~arnold/4353/CGSMGS.pdf



Matrix Operations -- Transpose +Determinant + Adjugate+ Inverse + Gram-Schimidt +LUP + QR + Eigen_第4张图片


老实说,这里被坑了好久...看到一个资料上面

http://www.math.iit.edu/~fass/477577_Chapter_4.pdf

MIT的lecture

http://ocw.mit.edu/courses/mathematics/18-335j-introduction-to-numerical-methods-fall-2010/lecture-notes/MIT18_335JF10_lec10a_hand.pdf

提供了一下算法.但是又没讲请促.我还以为q*是求伴随矩阵.坑我好久...我还去写了伴随矩阵的实现,

简直气愤...别看下面这个实现.越看越不相信自己...建议可以看我的Python实现...

Matrix Operations -- Transpose +Determinant + Adjugate+ Inverse + Gram-Schimidt +LUP + QR + Eigen_第5张图片


我自己根据公式给出的Python实现:

Matrix Operations -- Transpose +Determinant + Adjugate+ Inverse + Gram-Schimidt +LUP + QR + Eigen_第6张图片

    def gram_schimidt(self, A) :

        if A is None :
            return
        
        A_T = self.transpose(A)

        row = len(A_T)
        col = len(A_T[0])

        V = [[0 for i in range(0, col)] for j in range(0, row)]
        for i in range(0, row) :
            tmp_mat = [0 for x in range(0, col)]

            for j in range(0, col) :
                tmp = A_T[i][j]
                for k in range(0, i) :
                    factor = (1.0*self.dot_product(A_T[i], V[k])) / \
                             self.dot_product(V[k], V[k])
                    tmp -= factor*V[k][j]

                V[i][j] = tmp

        V = self.transpose(V)

        return V





Adjugate:伴随矩阵

Matrix Operations -- Transpose +Determinant + Adjugate+ Inverse + Gram-Schimidt +LUP + QR + Eigen_第7张图片


测试结果:

Matrix Operations -- Transpose +Determinant + Adjugate+ Inverse + Gram-Schimidt +LUP + QR + Eigen_第8张图片




Inverse : 矩阵求逆

基于行列变换去做矩阵求逆

Matrix Operations -- Transpose +Determinant + Adjugate+ Inverse + Gram-Schimidt +LUP + QR + Eigen_第9张图片

这里我实现了函数inverse(matrix),用来求解,给定参数matrix

Matrix Operations -- Transpose +Determinant + Adjugate+ Inverse + Gram-Schimidt +LUP + QR + Eigen_第10张图片

最后我测试的时候让逆矩阵和原来的矩阵做矩阵乘法.最后得到单位矩阵.经检验,求逆算法是正确的.

    def inverse(self, mat) :
        if mat is None :
            return

        # make sure that this matrix that you inputed is invertible
        if  self.determinant(mat) == 0 :
            print "ATTENTION! The determinant of matrix is ZERO"
            print "This matrix is uninvertible"
            return

        row = len(mat)
        col = len(mat[0])

        #matrix = copy.copy(mat)
        matrix = copy.deepcopy(mat)
#        matrix = [[0 for i in range(0, col)] for j in range(0, row)]
#        for i in range(0, row) :
#            for j in range(0, col) :
#                matrix[i][j] = mat[i][j]

        for i in range(0, row) :
            for j in range(0, col) :
                if i == j :
                    matrix[i] += [1]
                else :
                    matrix[i] += [0]

        row = len(matrix)
        col = len(matrix[0])

        for i in range(0, row) :
            if matrix[i][i] is 0 :
                for k in range(i+1, row) :
                    if matrix[k][i] is not 0 :
                        break

                if k is not i+1 :
                    for j in range(0, col) :
                        matrix[i][j], matrix[k][j] = matrix[k][j], matrix[i][j]

            for k in range(i+1, row) :
                if matrix[k][i] is not 0 :
                    times = (1.0*matrix[k][i])/matrix[i][i]
                    for j in range(i, col) :
                        matrix[k][j] /= times
                        matrix[k][j] -= matrix[i][j]

        for i in range(0, row) :
            for j in range(i+1, col/2) :
                if matrix[i][j] is not 0 :
                    times = matrix[i][j]/matrix[j][j]
                    for k in range(j, col) :
                        matrix[i][k] -= times * matrix[j][k]


        for i in range(0, row) :
            times = matrix[i][i]
            for j in range(0, col) :
                matrix[i][j] /= times

        output = [[0 for i in range(0, col/2)] for j in range(0, row)]
        for i in range(0, row) :
            for j in range(0, col/2) :
                output[i][j] = matrix[i][j+col/2]

        return output



QR decomposition :

Matrix Operations -- Transpose +Determinant + Adjugate+ Inverse + Gram-Schimidt +LUP + QR + Eigen_第11张图片


这个在我原来看来装逼度很高的矩阵分解也就是个纸老虎

首先对其进行Gram-schimidt正交化处理,然后就简答鸟,看下面这个运算demo

Matrix Operations -- Transpose +Determinant + Adjugate+ Inverse + Gram-Schimidt +LUP + QR + Eigen_第12张图片

向量组v由正交化过程求得,然后每个列向量除以自己的模值即可得到矩阵Q

利用Q是正交阵的特点,求得R矩阵

Matrix Operations -- Transpose +Determinant + Adjugate+ Inverse + Gram-Schimidt +LUP + QR + Eigen_第13张图片

哥们儿,别忘记鸟,计算机求解的都是数值解,数值解不一定等于解析解~!

Matrix Operations -- Transpose +Determinant + Adjugate+ Inverse + Gram-Schimidt +LUP + QR + Eigen_第14张图片


    def qr_decomposition(self, A) :
        if A is None :
            return

        orthogonal_mat = self.transpose(self.gram_schimidt(A))

        row = len(orthogonal_mat)
        col = len(orthogonal_mat[0])

        Q = [[0 for i in range(0, col)] for j in range(0, row)]
        for i in range(0, row) :
            mag = self.magnitude(orthogonal_mat[i])
            for j in range(0, col) :
                Q[i][j] = orthogonal_mat[i][j]/mag

        R = self.multiply(Q, A)
        Q = self.transpose(Q)

        return (Q, R)




关于LUP的理论分析去看CLRS吧.... 这里仅贴出自己的实现.

终于~ LUP不再那么神乎其神...


Matrix Operations -- Transpose +Determinant + Adjugate+ Inverse + Gram-Schimidt +LUP + QR + Eigen_第15张图片


Matrix Operations -- Transpose +Determinant + Adjugate+ Inverse + Gram-Schimidt +LUP + QR + Eigen_第16张图片 

Matrix Operations -- Transpose +Determinant + Adjugate+ Inverse + Gram-Schimidt +LUP + QR + Eigen_第17张图片

Eigen value and eigen vector :

看这里:

http://blog.csdn.net/cinmyheart/article/details/44086369



---------------


Python 实现:

"""
Programmer  :   EOF
Code date   :   2015.02.28
Code file   :   matrix.py

Code description :

    @transpose : return a matrix @A_T which is tranposed matrix of @A

    @lu_decomposition : return matrix @L and @U which are decomposed from matrix @A

    @plu_decomposition  : return matrix @P, @L and @U which are decomposed from matrix @A

"""
import copy
import numpy

class mat() :

    def transpose(self, A) :
        row = len(A)
        col = len(A[0])

        A_T = [[0 for i in range(0, row)] for j in range(0, col)]

        for i in range(0, row) :
            for j in range(0, col) :
                A_T[j][i] = A[i][j]

        return A_T

    def add(self, A, B) :
        if A is None or B is None :
            return

        row_A = len(A)
        col_A = len(A[0])
        row_B = len(B)
        col_B = len(B[0])

        if row_A != row_B or col_A != col_B :
            print "Are you kidding me? The matrixes that you inputed ",\
            "have different size. It's illegal to add these matries together"
            return

        output = [[0 for i in range(0, col_A)] for j in range(0, row_A)]
        for i in range(0, row_A) :
            for j in range(0, col_A) :
                output[i][j] = A[i][j] + B[i][j]

        return output

    def sub(self, A, B) :
        if A is None or B is None :
            return

        row_A = len(A)
        col_A = len(A[0])
        row_B = len(B)
        col_B = len(B[0])

        if row_A != row_B or col_A != col_B :
            print "Are you kidding me? The matrixes that you inputed ",\
            "have different size. It's illegal to sub these matries together"
            return

        output = [[0 for i in range(0, col_A)] for j in range(0, row_A)]
        for i in range(0, row_A) :
            for j in range(0, col_A) :
                output[i][j] = A[i][j] - B[i][j]

        return output

    def multiply(self, A, B) :
        if A is None or B is None :
            return

        if len(A[0]) is not len(B) :
            print "The size of the two inputed matrix is illegally ",\
                    "to do multiplication in matrix"
            return

        row_A = len(A)
        col_A = len(A[0])
        col_B = len(B[0])

        output = [[0 for i in range(0, col_B)] for j in range(0, row_A)]

        for i in range(0, row_A) :
            for j in range(0, col_B) :
                sum_val = 0
                for k in range(0, col_A) :
                    sum_val += A[i][k] * B[k][j]

                output[i][j] = sum_val

        return output

    def dot_product(self, A, B) :
        if A is None or B is None :
            return

        len_A = len(A)
        len_B = len(B)

        if len_A != len_B :
            print "It's Illegal to do dot product with the two matrixes",
            "which have different size"
            return

        sum_val = 0
        for i in range(0, len_A) :
            sum_val += A[i]*B[i]

        return sum_val

    def magnitude(self, A) :
        ret_val = self.dot_product(A, A)
        return numpy.sqrt(ret_val)

    def gram_schimidt(self, A) :

        if A is None :
            return
        
        A_T = self.transpose(A)

        row = len(A_T)
        col = len(A_T[0])

        V = [[0 for i in range(0, col)] for j in range(0, row)]
        for i in range(0, row) :
            tmp_mat = [0 for x in range(0, col)]

            for j in range(0, col) :
                tmp = A_T[i][j]
                for k in range(0, i) :
                    factor = (1.0*self.dot_product(A_T[i], V[k])) / \
                             self.dot_product(V[k], V[k])
                    tmp -= factor*V[k][j]

                V[i][j] = tmp

        V = self.transpose(V)

        return V


    def adjugate(self, A) :
        row = len(A)
        col = len(A[0])

        output = [[0 for x in range(0, col)] for y in range(0, row)]
        for i in range(0, row) :
            for j in range(0, col) :
                tmp_mat = [[0 for x in range(0, col-1)] for y in range(0, row-1)]

                for m in range(0, row) :
                    for n in range(0, col) :
                        if m < i and n < j :
                            tmp_mat[m][n] = A[m][n]
                        elif m > i and n < j :
                            tmp_mat[m-1][n] = A[m][n]
                        elif m < i and n > j :
                            tmp_mat[m][n-1] = A[m][n]
                        elif m > i and n > j :
                            tmp_mat[m-1][n-1] = A[m][n]

                det_val = self.determinant(tmp_mat)
                det_val *= (-1)**(i+j)
                
                output[i][j] = det_val

        output = self.transpose(output)

        return output


    def qr_decomposition(self, A) :
        if A is None :
            return

        orthogonal_mat = self.transpose(self.gram_schimidt(A))

        row = len(orthogonal_mat)
        col = len(orthogonal_mat[0])

        Q = [[0 for i in range(0, col)] for j in range(0, row)]
        for i in range(0, row) :
            mag = self.magnitude(orthogonal_mat[i])
            for j in range(0, col) :
                Q[i][j] = orthogonal_mat[i][j]/mag

        R = self.multiply(Q, A)
        Q = self.transpose(Q)

        return (Q, R)


    def lup_solve(self, L, U, pi, b) :
        n = len(self.L)
        x = [0 for i in range(0, n)]
        y = [0 for i in range(0, n)]
        for i in range(0, n) :
            tmp = 0
            for j in range(0, i-1) :
                tmp += L[i][j] * y[j]

            y[i] = b[ pi[i] ] - tmp

        for i in range(n-1, -1, -1) :
            tmp = 0
            for j in range(i+1, n) :
                tmp += U[i][j] * x[j]
            x[i] = (y[i] - tmp)/u[i][i]

        return x
    

    def lu_decomposition(self, A) :
        n = len(A)
        a = A

        self.L = [[0 for i in range(0, n)] for j in range(0, n)]
        self.U = [[0 for i in range(0, n)] for j in range(0, n)]

        for k in range(0, n) :
            self.U[k][k] = a[k][k]

            for i in range(k+1, n) :
                self.L[i][k] = a[i][k]/self.U[k][k]
                self.U[k][i] = a[k][i]

            for i in range(k+1, n) :
                for j in range(k+1, n) :
                    a[i][j] = a[i][j] - self.L[i][k]*self.U[k][j]

        return (self.L, self.U)


    def lup_decomposition(self, A) :
        n = len(A)
        a = A

        pi = [i for i in range(0, n)]

        for k in range(0, n) :
            p = 0
            for i in range(k, n) :
                if abs(a[i][k]) > p :
                    p = abs(a[i][k])
                    k_prime = i

            if p is 0 :
                print "singular matrix"
                return 

            pi[k], pi[k_prime]  = pi[k_prime], pi[k]

            for i in range(0, n) :
                a[k][i], a[k_prime][i] = a[k_prime][i], a[k][i]

            for i in range(k+1, n) :
                a[i][k] /= (a[k][k] * 1.0)
                for j in range(k+1, n) :
                    a[i][j] -= a[i][k] * a[k][j]

        self.P = [[ 0 for i in range(0, len(pi))] for j in range(0, len(pi))]
        for i in range(0, len(pi)) :
            self.P[i][ pi[i] ] = 1

        self.L = [[0 for i in range(0, n)] for j in range(0, n)]
        self.U = [[0 for i in range(0, n)] for j in range(0, n)]

        row = len(self.L)
        col = len(self.L[0])
        for i in range(0, row) :
            for j in range(0, col) :
                if j < i :
                    self.L[i][j] = a[i][j]
                elif j == i :
                    self.L[i][j] = 1
                    self.U[i][j] = a[i][j]
                else :
                    self.U[i][j] = a[i][j]

        return (self.P, self.L, self.U)


    def determinant(self, matrix) :
        row = len(matrix)
        col = len(matrix[0])

        if row == 1 :
            return matrix
        elif row == 2 :
            return matrix[0][0]*matrix[1][1] - matrix[1][0] * matrix[0][1]

        ret_val = 0
        for i in range(0, col) :
            tmp_mat = [[0 for x in range(0, col-1)] for y in range(0, row-1)]

            for m in range(0, row-1) :
                n = 0
                while n < col-1 :
                    if n < i :
                        tmp_mat[m][n] = matrix[m+1][n]
                    else :
                        tmp_mat[m][n] = matrix[m+1][n+1] 
                    n += 1

            ret_val += ((-1)**(i)) * matrix[0][i] * \
                       self.determinant(tmp_mat)

        return ret_val


    def inverse(self, mat) :
        if mat is None :
            return

        # make sure that this matrix that you inputed is invertible
        if  self.determinant(mat) == 0 :
            print "ATTENTION! The determinant of matrix is ZERO"
            print "This matrix is uninvertible"
            return

        row = len(mat)
        col = len(mat[0])

        #matrix = copy.copy(mat)
        matrix = copy.deepcopy(mat)
#        matrix = [[0 for i in range(0, col)] for j in range(0, row)]
#        for i in range(0, row) :
#            for j in range(0, col) :
#                matrix[i][j] = mat[i][j]

        for i in range(0, row) :
            for j in range(0, col) :
                if i == j :
                    matrix[i] += [1]
                else :
                    matrix[i] += [0]

        row = len(matrix)
        col = len(matrix[0])

        for i in range(0, row) :
            if matrix[i][i] is 0 :
                for k in range(i+1, row) :
                    if matrix[k][i] is not 0 :
                        break

                if k is not i+1 :
                    for j in range(0, col) :
                        matrix[i][j], matrix[k][j] = matrix[k][j], matrix[i][j]

            for k in range(i+1, row) :
                if matrix[k][i] is not 0 :
                    times = (1.0*matrix[k][i])/matrix[i][i]
                    for j in range(i, col) :
                        matrix[k][j] /= times
                        matrix[k][j] -= matrix[i][j]

        for i in range(0, row) :
            for j in range(i+1, col/2) :
                if matrix[i][j] is not 0 :
                    times = matrix[i][j]/matrix[j][j]
                    for k in range(j, col) :
                        matrix[i][k] -= times * matrix[j][k]


        for i in range(0, row) :
            times = matrix[i][i]
            for j in range(0, col) :
                matrix[i][j] /= times

        output = [[0 for i in range(0, col/2)] for j in range(0, row)]
        for i in range(0, row) :
            for j in range(0, col/2) :
                output[i][j] = matrix[i][j+col/2]

        return output


    def eig(self, A) :
        if A is None :
            return

        tmp_mat = copy.deepcopy(A)
        for i in range(0, 20) :
            (Q, R) = self.qr_decomposition(tmp_mat)
            tmp_mat = self.multiply(R, Q)

        row = len(tmp_mat)
        col = len(tmp_mat[0])
        for i in range(0, row) :
            for j in range(0, col) :
                if i != j :
                    tmp_mat[i][j] = 0

        eig_vec = self.inverse(self.sub(A, tmp_mat))
        return (tmp_mat, eig_vec)


    def show(self, matrix) :

        if matrix is None :
            return 

        row = len(matrix)
        col = len(matrix[0])
        
        for i in range(0, row) :
            for j in range(0, col) :
                print "\t%1.2f" % matrix[i][j],
            print

        print "\n\n"


#-----------------for testing------------------------------------

#matrix = [[2,3,1,5], [6,13,5,19], [2,19,10,23],[4,10,11,31]]
matrix = [[2,0,2,0.6], [3,3,4,-2], [5,5,4,2], [-1,-2,3.4,-1]]

m = mat()

print "The determinant of matrix @mat_1 :"
mat_1 = [[1, 0, 0], [0, 2, 0], [0, 0, 3]]
m.show(mat_1)
print m.determinant(mat_1)

print "The determinant of matrix @mat_2 :"
mat_2 = [[1, 5, 0], [2, 4, -1], [0, -2, 0]]
m.show(mat_2)
print m.determinant(mat_2)

print "The input matrix is \n"
m.show(matrix)

print "After transpose\n"
m.show(m.transpose(matrix))

(P, L, U) = m.lup_decomposition(matrix)

print "After PLU decomposition, we got matrixes"

print "P:"
m.show(P)

print "L:"
m.show(L)

print "U:"
m.show(U)

inv_mat = m.inverse(matrix)
print "The inverse matrix of the inputed matrix is "
m.show(inv_mat)
print "Output"
m.show(m.multiply(inv_mat, matrix))

mat_1 = [[1,2,3],[4,5,6],[7,8,9]]
print "The inputed matrix"
m.show(mat_1)
print "The adjugate matrix of the inputed matrix is "
m.show(m.adjugate(mat_1))

mat_1 = [[1,0,0],[1,1,0],[1,1,1],[1,1,1]]
print "The inputed matrix"
m.show(mat_1)
print "The gram chimidt matrix of the inputed matrix is "
m.show(m.gram_schimidt(mat_1))

print "The inputed matrix"
m.show(mat_1)
print "The adjugate matrix of the inputed matrix is "
(Q, R) = m.qr_decomposition(mat_1)
m.show(Q)
m.show(R)

#mat_1 = [[2, 3], [3, -6]]
mat_1 = [[2, 1], [1, 2]]
print "The inputed matrix"
m.show(mat_1)
print "The eig value matrix of the inputed matrix is "
(eig_val, eig_vector) = m.eig(mat_1)
m.show(eig_val)
m.show(eig_vector)




waiting for updates ... ...

2015.02.28 更新了行列式求值的实现.determinant()

2015.03.01 更新了矩阵求逆的实现.inverse()

2015.03.03 更新了矩阵求伴随矩阵的实现adjugate()

2015.03.05 更新了矩阵Gram-Schimit()正交化的实现.

2015.03.05 更新了矩阵的QR分解的实现

2015.03.05 更新了矩阵的特征值和特征向量的实现eig()












再美好也经不住遗忘,再悲伤也抵不过时光

摄于二零一五年大年初二

Matrix Operations -- Transpose +Determinant + Adjugate+ Inverse + Gram-Schimidt +LUP + QR + Eigen_第18张图片




你可能感兴趣的:(Algorithm,python,Matrix)