1 LU分解
三角分解常用于数值分析中,是高斯消元法的一种表达形式,可以方便的求解线性方程组,求逆矩阵,计算行列式的值。
矩阵的三角分解体现了高斯消元的一个过程,将实矩阵拓展成A:E的形式,可以很方便的求解矩阵的逆,而如果我们将A变成一个下三角矩阵事,在A的所有顺序主子式不为0的情况下总是有E变为一上三角矩阵。不妨认为下三角矩阵与上三角矩阵分别为L,U,则有A=LU。可以认为U为A到L的线性变换的矩阵。
在高斯消元法中,我们将右侧向量b与A写在一起作为一个增广矩阵进行同步的操作,这就默认了对A与b的操作数是相等的且每换一个b就要重复一遍对A的操作。然而,当其右侧向量b发生变化时,需要重新进行消元,而分解后的矩阵进行回代操作的过程会明显快于重新消元。所以对A进行一次完整的消元操作后再将b回代。而所谓的完整消元就是将A进行线性变换成一个三角矩阵的过程(这里不妨认为是下三角矩阵),而其变换所对应的矩阵又是可求的,这就为求解方程组提供了便利。
U分解的步骤如下:
1.求U留E:沿用高斯消元法,将A化为U,不同的是,变换过程中左边乘上的每一个E都要记录下来;
2.逆E为L:将用到的E各自求逆(取含变换操作的元素的相反数)再逆序相乘(将消元乘数按照原来的位置写到一起,再补齐左上-右下对角线上的1和对角线上方的0),乘积即为L:
E求逆的简便方法和乘积求逆的运算法则在#3中已经提到。
逆序相乘等价于归置消元乘数于下三角矩阵中是一个常用结论,记忆使用可以简化运算。
乘积为L的依据是:假设E为所有E的乘积,EA=U可变形为E(-1)EA=E(-1)U=IA=A=LU,其中L=E(-1)。
利用A的LU分解解线性方程组的过程为将Ax=b等价变形成(LU)x=b,根据结合律有L(Ux)=b,再解Ly=b中的y,最后解Ux=y得到线性方程组的解。
提供一种快速LU分解矩阵的方法,如下图。
基于这种求解方法,大佬(Doolittle)发明了一种算法进行分解。
#include<algorithm>
#include<iostream>
using namespace std;
/*这里以20*20矩阵为例*/
const int Size = 20;
double a[Size][Size];//A
double l[Size][Size];//L
double u[Size][Size];//U
double sumLrkUki(int r, int i) {
double re = 0.0;
for (int k = 0; k < r; k++) {
re += l[r][k] * u[k][i];
}
return re;
}
double sumLikUkr(int r, int i) {
double re = 0.0;
for (int k = 0; k < r; k++) {
re += l[i][k] * u[k][r];
}
return re;
}
void countLU() {
for (int i = 0; i < Size; i++) {
u[0][i] = a[0][i];
l[i][0] = a[i][0] / u[0][0];
}
for (int r = 1; r < Size; r++) {
for (int i = r; i < Size; i++) {
u[r][i] = a[r][i] - sumLrkUki(r, i);
if (i == r) l[r][r] = 1;
else if
(r == Size) l[Size][Size] = 1;
else
l[i][r] = (a[i][r] - sumLikUkr(r, i)) / u[r][r];
}
}
}
void setData() {
for (int i = 0; i < Size; i++) {
for (int j = 0; j < Size; j++) {
cin >> a[i][j];
}
}
}