Bootstrap

4.3 Cholesky分解

  柯列斯基分解cholesky decomposition只能用于实对称正定矩阵,实对称正定矩阵一般用于定义内积。柯列斯基分解是将矩阵分解为如下形式:
A = G G T A=GG^T A=GGT
  其中 G G G是下三角矩阵。柯列斯基分解主要有两种算法:LU分解法和递推算法。

LU分解法

  LU分解法主要分三步:

  1. 求矩阵的Doolittle分解 A = L U A=LU A=LU
  2. 因为是对称矩阵,所以 U = D L T U=DL^{T} U=DLT D D D U U U的对角线元素构成的对角阵。
  3. 算出 G = L D G=L\sqrt{D} G=LD ,虽然我们没有学过矩阵函数,但是对角阵开根号直接把对角线各个元素开根号就行了。因为是正定矩阵,所以不存在对负数开根号的问题。
      对于这种算法,Python代码比较简单:
    # 柯列斯基分解
    def cholesky(self):
        l, u = self.lu_decomposition()
        # u的对角线元素开根号
        n = len(self.__vectors)
        d_array = [
            [math.sqrt(u.vectors[i][j]) if i == j else 0 for j in range(n)]
            for i in range(n)
        ]
        d = Matrix(d_array)
        return l * d, d * u

递推算法

  递推算法利用的是两个分解出来的矩阵是互为转置的特点进行的。按列进行主循环迭代,每个迭代步骤主要分两小步:

  1. 求出对角线元素;
  2. 再求出该列对角线元素下方其他元素。

  对角线元素使用公式就好了。利用以下迭代公式:
g i i = a i i − ∑ k = 1 i − 1 g i k 2 g_{ii}=\sqrt{a_{ii}-\sum_{k=1}^{i-1}g_{ik}^2} gii=aiik=1i1gik2
  非对角线元素使用下面这个公式:
g j i = 1 g i i ( a i j − ∑ k = 1 i − 1 g i k g j k ) g_{ji}=\frac1{g_{ii}}(a_{ij}-\sum_{k=1}^{i-1}g_{ik}g_{jk}) gji=gii1(aijk=1i1gikgjk)
  算法清晰了,python代码就容易了:

    # 柯列斯基分解迭代法
    def cholesky_iterate(self):
        n = len(self.__vectors)
        array = [[0 for _ in range(n)] for _ in range(n)]
        for i in range(n):
            # 对角线元素
            s = 0
            for k in range(i):
                s += array[k][i] * array[k][i]
            array[i][i] = math.sqrt(self.__vectors[i][i] - s)
            # 非对角线元素
            for j in range(i+1,n):
                s1 = 0
                for k in range(i):
                    s1 += array[k][i] * array[k][j]
                array[i][j] = (self.__vectors[j][i] - s1) / array[i][i]

        matrix = Matrix(array)
        return matrix, Matrix(matrix.transpose())
;