LU分解求逆
文章转自:
https://www.cnblogs.com/bigmonkey/p/9555710.html
https://blog.csdn.net/xx_123_1_rj/article/details/39553809
什么是LU分解
在线性代数中, LU分解是矩阵分解的一种,可以将一个矩阵分解为一个单位下三角矩阵和一个上三角矩阵的乘积(有时是它们和一个置换矩阵的乘积)
如果有一个矩阵A,将A表示成下三角矩阵L和上三角矩阵U的乘积,称为A的LU分解。
更进一步,我们希望下三角矩阵的对角元素都为1:
LU分解的步骤
上一章讲到,对于满秩矩阵A来说,通过左乘一个消元矩阵,可以得到一个上三角矩阵U。
可以看到,L实际上就是消元矩阵的逆。容易知道二阶矩阵的逆:
现在假设A是一个3×3矩阵,在不考虑行交换的情况下,通过消元得到上三角矩阵的过程是:
LU 分解的前提
并非所有矩阵都能进行LU分解,能够LU分解的矩阵需要满足以下三个条件:
- 矩阵是方阵(LU分解主要是针对方阵);
- 矩阵是可逆的,也就是该矩阵是满秩矩阵,每一行都是独立向量;
- 消元过程中没有0主元出现,也就是消元过程中不能出现行交换的初等变换
示例
如果A存在LU分解存,a,b满足什么条件?
使用消元法逐一消去主元:
由于E31 中出现了 –b/a,所以a ≠ 0
b可以是任意常数。
具体的算法流程可以是:
1)进行LU分解;
2)对分解后的L阵(下三角矩阵)和U阵(上三角矩阵)进行求逆;
3)L阵的逆矩阵和U阵的逆矩阵相乘,即可求得原来矩阵的逆。即:
程序实现如下:
1 #include<stdio.h> 2 #include <string.h> 3 #define N 4 4 void main() 5 { 6 float a[N][N]; 7 float L[N][N],U[N][N],out[N][N], out1[N][N]; 8 float r[N][N],u[N][N]; 9 memset( a , 0 , sizeof(a)); //初始化 10 memset( L , 0 , sizeof(L)); 11 memset( U , 0 , sizeof(U)); 12 memset( r , 0 , sizeof(r)); 13 memset( u , 0 , sizeof(u)); 14 int n=N; 15 int k,i,j; 16 int flag=1; 17 float s,t; 18 ////////////////////input a matrix//// 19 printf("input A=\n"); 20 for(i=0;i<n;i++) 21 for(j=0;j<n;j++) 22 scanf("%f",&a[i][j]); 23 //////////////////figure the input matrix////////////////////////// 24 printf("输入矩阵:\n"); 25 for(i=0;i<n;i++) 26 { 27 for (j = 0; j < n; j++) 28 { 29 printf("%lf ", a[i][j]); 30 } 31 printf("\n"); 32 } 33 for(j=0;j<n;j++) 34 a[0][j]=a[0][j]; //计算U矩阵的第一行 35 36 for(i=1;i<n;i++) 37 a[i][0]=a[i][0]/a[0][0]; //计算L矩阵的第1列 38 for(k=1;k<n;k++) 39 { 40 for(j=k;j<n;j++) 41 { 42 s=0; 43 for (i=0;i<k;i++) 44 s=s+a[k][i]*a[i][j]; //累加 45 a[k][j]=a[k][j]-s; //计算U矩阵的其他元素 46 } 47 for(i=k+1;i<n;i++) 48 { 49 t=0; 50 for(j=0;j<k;j++) 51 t=t+a[i][j]*a[j][k]; //累加 52 a[i][k]=(a[i][k]-t)/a[k][k]; //计算L矩阵的其他元素 53 } 54 } 55 for(i=0;i<n;i++) 56 for(j=0;j<n;j++) 57 { 58 if(i>j) 59 { 60 L[i][j]=a[i][j]; 61 U[i][j]=0; 62 }//如果i>j,说明行大于列,计算矩阵的下三角部分,得出L的值,U的//为0 63 else 64 { 65 U[i][j]=a[i][j]; 66 if(i==j) 67 L[i][j]=1; //否则如果i<j,说明行小于列,计算矩阵的上三角部分,得出U的//值,L的为0 68 else 69 L[i][j]=0; 70 } 71 } 72 if(U[1][1]*U[2][2]*U[3][3]*U[4][4]==0) 73 { 74 flag=0; 75 printf("\n逆矩阵不存在");} 76 if(flag==1) 77 { 78 /////////////////////求L和U矩阵的逆 79 for (i=0;i<n;i++) /*求矩阵U的逆 */ 80 { 81 u[i][i]=1/U[i][i];//对角元素的值,直接取倒数 82 for (k=i-1;k>=0;k--) 83 { 84 s=0; 85 for (j=k+1;j<=i;j++) 86 s=s+U[k][j]*u[j][i]; 87 u[k][i]=-s/U[k][k];//迭代计算,按列倒序依次得到每一个值, 88 } 89 } 90 for (i=0;i<n;i++) //求矩阵L的逆 91 { 92 r[i][i]=1; //对角元素的值,直接取倒数,这里为1 93 for (k=i+1;k<n;k++) 94 { 95 for (j=i;j<=k-1;j++) 96 r[k][i]=r[k][i]-L[k][j]*r[j][i]; //迭代计算,按列顺序依次得到每一个值 97 } 98 } 99 /////////////////绘制矩阵LU分解后的L和U矩阵/////////////////////// 100 printf("\nLU分解后L矩阵:"); 101 for(i=0;i<n;i++) 102 { 103 printf("\n"); 104 for(j=0;j<n;j++) 105 printf(" %lf",L[i][j]); 106 } 107 printf("\nLU分解后U矩阵:"); 108 for(i=0;i<n;i++) 109 { 110 printf("\n"); 111 for(j=0;j<n;j++) 112 printf(" %lf",U[i][j]); 113 } 114 printf("\n"); 115 ////////绘制L和U矩阵的逆矩阵 116 printf("\nL矩阵的逆矩阵:"); 117 for(i=0;i<n;i++) 118 { 119 printf("\n"); 120 for(j=0;j<n;j++) 121 printf(" %lf",r[i][j]); 122 } 123 printf("\nU矩阵的逆矩阵:"); 124 for(i=0;i<n;i++) 125 { 126 printf("\n"); 127 for(j=0;j<n;j++) 128 printf(" %lf",u[i][j]); 129 } 130 printf("\n"); 131 //验证将L和U相乘,得到原矩阵 132 printf("\nL矩阵和U矩阵乘积\n"); 133 for(i=0;i<n;i++) 134 { 135 for(j=0;j<n;j++) 136 { 137 out[i][j]=0; 138 } 139 } 140 for(i=0;i<n;i++) 141 { 142 for(j=0;j<n;j++) 143 { 144 for(k=0;k<n;k++) 145 { 146 out[i][j]+=L[i][k]*U[k][j]; 147 } 148 } 149 } 150 for(i=0;i<n;i++) 151 { 152 for(j=0;j<n;j++) 153 { 154 printf("%lf\t",out[i][j]); 155 } 156 printf("\r\n"); 157 } 158 //////////将r和u相乘,得到逆矩阵 159 printf("\n原矩阵的逆矩阵:\n"); 160 for(i=0;i<n;i++) 161 { 162 for(j=0;j<n;j++) 163 {out1[i][j]=0;} 164 } 165 for(i=0;i<n;i++) 166 { 167 for(j=0;j<n;j++) 168 { 169 for(k=0;k<n;k++) 170 { 171 out1[i][j]+=u[i][k]*r[k][j]; 172 } 173 } 174 } 175 for(i=0;i<n;i++) 176 { 177 for(j=0;j<n;j++) 178 { 179 printf("%lf\t",out1[i][j]); 180 } 181 printf("\r\n"); 182 } 183 } 184 }