09-27:LU分解、追赶法和Cholesky分解

你有你的计划,世界另有计划。

列主元消去法是对高斯顺序消去法在主元为0或较小值时的修正;LU分解本质上就是高斯消去法;追赶法适用于三对角矩阵;Cholesky分解是可以在对称正定矩阵情况下比列主元消去法速度提高大约一倍,数据存储内存减少一半。
高斯顺序消去和列主元消去法的代码已经写过。今天写LU分解、追赶法和Cholesky分解。主要参考今天数学课上的PPT课件。

1.LU分解

原理不多说,可以参考相关资料。直接上代码:

def getLandU(matA):
    '''
    输入:
    A:系数矩阵;array格式,且数值类型必须为浮点数,否则会出现截断误差。
    输出:
    LU分解中的L和U矩阵
    '''
    if matA[0,0]==0: 
        print('不符合要求!需要换行操作。')
    else:
        numRows = matA.shape[0] 
        matL = np.identity(numRows)         # 准备给L矩阵用
        for row in np.arange(0,numRows-1):  # 前n-1行,row代表第几行
            for k in range(row+1,numRows):  # 在第row行的情况下,遍历剩下的行
                matL[k,row] = matA[k,row]/matA[row,row]   # 获得L矩阵
                if matA[k,row] != 0:
                    matA[k,:]=matA[k,:] - (matA[k,row]/matA[row,row])*matA[row,:]
    return matL,matA   # matL为L矩阵,matA变为U矩阵

输入一个系数矩阵A,输出直接得到L矩阵和U矩阵。拿今天上课中例题2.3.1来测试一下。

A = np.array([[2,1,-2],[4,0,-1],[0,3,2]],dtype=float)
b = np.array([[1],[7],[-1]],dtype=float)
'''
A = array([[ 2. ,  1. , -2. ],
           [ 0. , -2. ,  3. ],
           [ 0. ,  0. ,  6.5]])
'''
L,U = getLandU(A)

得到如下结果:

'''
L = array([[ 1. ,  0. ,  0. ],
           [ 2. ,  1. ,  0. ],
           [ 0. , -1.5,  1. ]])
U = array([[ 2. ,  1. , -2. ],
           [ 0. , -2. ,  3. ],
           [ 0. ,  0. ,  6.5]])    
'''

跟课件上一样,说明效果不错。下面写LDU分解,只需要在LU分解的基础上做一些修改即可。以下是代码,就比上面多了三四行。

def getL_D_U(matA):
    '''
    输入:
    A:系数矩阵;array格式,且数值类型必须为浮点数,否则会出现截断误差。
    输出:
    LDU分解中的L、D和U矩阵
    '''
    if matA[0,0]==0: 
        print('不符合要求!需要换行操作。')
    else:
        numRows = matA.shape[0] 
        matL = np.identity(numRows)         # 准备给L矩阵用
        for row in np.arange(0,numRows-1):  # 前n-1行,row代表第几行
            for k in range(row+1,numRows):  # 在第row行的情况下,遍历剩下的行
                matL[k,row] = matA[k,row]/matA[row,row]   # 获得L矩阵
                if matA[k,row] != 0:
                    matA[k,:]=matA[k,:] - (matA[k,row]/matA[row,row])*matA[row,:]
        matD = np.identity(numRows)
        for i in range(numRows):
            matD[i,i] = matA[i,i]
            matA[i,:] = matA[i,:]/matA[i,i]
    return matL,matD,matA   # matL为L矩阵,matD为D矩阵,matA变为U矩阵

同样测试一下:

A = np.array([[2,1,-2],[4,0,-1],[0,3,2]],dtype=float)
L,D,U = getL_D_U(A)
'''
L = array([[ 1. ,  0. ,  0. ],
           [ 2. ,  1. ,  0. ],
           [ 0. , -1.5,  1. ]])
D = array([[ 2. ,  0. ,  0. ],
           [ 0. , -2. ,  0. ],
           [ 0. ,  0. ,  6.5]])
U = array([[ 1. ,  0.5, -1. ],
           [-0. ,  1. , -1.5],
           [ 0. ,  0. ,  1. ]])
'''

可见,结果是正确的。

2.追赶法

追赶法使用于三对角矩阵。实际上,对于解三对角矩阵,直接用上面的LU分解再求解已经没什么问题了,那么为什么还要弄一个追赶法呢?这是因为如果三对角矩阵是一种很普遍的矩阵形式,那么就有必要编写一套专门求解三对角矩阵LU分解的算法,这样可以提高计算效率,还可以降低计算机内存的存储空间。
追赶法本质是LU分解的一种特例,这里利用其定义来编写函数。


追赶法.png

以下是我的代码。你会发现比上面的LU分解少了一层循环,速度必然提升。不过代码里面的索引取值比较绕,可能要多花一点时间搞明白。

def catchUp(matA):
    '''
    只适用于三对角矩阵!
    输入:
    A:系数矩阵;array格式,且数值类型必须为浮点数,否则会出现截断误差。
    输出:
    LU分解中的L和U矩阵
    '''
    numRows = matA.shape[0] 
    matL = np.identity(numRows)         # 准备给L矩阵用
    matU = np.zeros((numRows,numRows))  # 准备给U矩阵用
    matU[0,0] = matA[0,0]               # 初始
    for row in np.arange(0,numRows-1):  # 前n-1行,row代表第几行
        matL[row + 1,row] = matA[row + 1,row]/matU[row,row]   # L的递推
        matU[row+1,row+1] = matA[row+1,row+1]-matL[row + 1,row]*matA[row,row+1] # U的递推,对角部分
        matU[row,row+1] = matA[row,row+1]
    return matL,matU   # matL为L矩阵,matD为D矩阵,matA变为U矩阵

这里用《数值方法》51页的例题2.3.2来做测试。

A = np.array([[2,-1,0,0,0],[-1,2,-1,0,0],[0,-1,2,-1,0],[0,0,-1,2,-1],[0,0,0,-1,2]],dtype=float)
'''
A = array([[ 2., -1.,  0.,  0.,  0.],
           [-1.,  2., -1.,  0.,  0.],
           [ 0., -1.,  2., -1.,  0.],
           [ 0.,  0., -1.,  2., -1.],
           [ 0.,  0.,  0., -1.,  2.]])
'''
L,U = catchUp(A)

得到的结果如下:

'''
L = array([[ 1.        ,  0.        ,  0.        ,  0.        ,  0.        ],
           [-0.5       ,  1.        ,  0.        ,  0.        ,  0.        ],
           [ 0.        , -0.66666667,  1.        ,  0.        ,  0.        ],
           [ 0.        ,  0.        , -0.75      ,  1.        ,  0.        ],
           [ 0.        ,  0.        ,  0.        , -0.8       ,  1.        ]])
U = array([[ 2.        , -1.        ,  0.        ,  0.        ,  0.        ],
           [ 0.        ,  1.5       , -1.        ,  0.        ,  0.        ],
           [ 0.        ,  0.        ,  1.33333333, -1.        ,  0.        ],
           [ 0.        ,  0.        ,  0.        ,  1.25      , -1.        ],
           [ 0.        ,  0.        ,  0.        ,  0.        ,  1.2       ]])
'''

可以看到,得到的结果和书上一致。

3.Cholesky分解

Cholesky分解是在矩阵式对称正定矩阵的情况下,只需要分解出L矩阵就可以实现,L乘于L的转置即可以等于系数矩阵A。
这里参考如下的计算公式:


Cholesky.png

以下是我的代码,直接分解出L矩阵。

def Cholesky(matA):
    '''
    只适对称正定矩阵!
    输入:
    A:系数矩阵;array格式,且数值类型必须为浮点数,否则会出现截断误差。
    输出:
    L矩阵
    '''
    numRows = matA.shape[0] 
    matL = np.zeros((numRows,numRows))  
    for row in np.arange(0,numRows):  
        matL[row,row] = (matA[row,row] - np.sum([s**2 for s in matL[row,0:row]]))**0.5  # 公式2.3.17
        for k in np.arange(row+1,numRows):
            matL[k,row] = (matA[k,row] - np.sum(np.dot(matL[k,0:row],matL[k-1,0:row])))/matL[row,row] # 公式2.3.18
    return matL   # matL所求

用书上例题2.3.3来测试一下。

A = np.array([[4,-1,1],[-1,4.25,2.75],[1,2.75,3.5]],dtype=float)
'''
A = array([[ 4.  , -1.  ,  1.  ],
           [-1.  ,  4.25,  2.75],
           [ 1.  ,  2.75,  3.5 ]])
'''
L = Cholesky(A)

得到结果如下。并且用L乘于L的转置也得到了原来的系数矩阵A。

'''
L = array([[ 2. ,  0. ,  0. ],
           [-0.5,  2. ,  0. ],
           [ 0.5,  1.5,  1. ]])
'''
reback = np.dot(L,L.T)
'''
reback = array([[ 4.  , -1.  ,  1.  ],
                [-1.  ,  4.25,  2.75],
                [ 1.  ,  2.75,  3.5 ]])
'''

结果与书上一致。

今日课上所讲的三种分解全部写完。今天所讲的三种分解,本质都是为了减少运算步骤,加快计算机运行线性方程组求解的速度。如果再考虑数据的存储的话,还可以减少内存的占用。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271