文章轉自:
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 }