本節我們討論如何用LUP分解法求解線性方程組,對於含有n個未知變量x1,x2,x3,…,xn的線性方程組:
同時滿足方程組中所有方程的一個數值集:x1,x2,…,xn稱為方程組的解。
將方程組改寫成矩陣向量等式:
記為:
Ax=b
如果A為非奇異矩陣,那么A存在逆矩陣,亦即方程組有解。
LUP分解的思想是找出三個n*n的矩陣,L、U和P,滿足
PA=LU
其中,L是一個單位下三角矩陣,U是一個上三角矩陣,P是一個置換矩陣。則稱滿足上述等式的L、U和P為矩陣A的LUP分解。
等式Ax=b兩邊同乘以P,變形為PAx=Pb,亦即:
LUx=Pb
設y=Ux,其中x就是我們要求的向量解。我們首先通過正向替換求解下三角系統:
Ly=Pb
得到未知變量y。然后,通過正向替換求解上三角系統:
Ux=y
得到未知變量x。
由於置換矩陣P是可逆的,等式PA=LU兩邊同乘以P-1,得:
A=P-1LU
=P-1Ly
=P-1Pb
=b
於是x就是Ax=b的解。
調用方法:
linear::CLinearEqualtion l(3); l.init_A("A.txt"); l.init_b("b.txt"); l.lu_decomposition(); l.lup_solve(); l.show_y(); l.show_x(); l.save_solution();
C++實現:
#include <iostream> #include <vector> #include <cassert> #include <fstream> using namespace std; namespace linear { #define array_1(__type) std::vector<__type> #define array_2(__type) std::vector<array_1(__type)> class CLinearEqualtion { /* 使用方法: 1. 定義計算方程組的類對象,並初始化其系數矩陣的大小 linear::CLinearEqualtion l(3); 2. 讀取系數陣 A l.init_A("A.txt"); 3. 讀取 b l.init_b("b.txt"); 4. 對系數矩陣進行lu分解 l.lu_decomposition(); 5. 求解方程組 l.lup_solve(); 6. 顯示反向替換的解 l.show_y(); 7. 顯示正向替換的解 l.show_x(); 8. 保存方程的解 l.save_solution(); A.txt 1 5 4 2 0 3 5 8 2 b.txt 12 9 5 x[0] = -0.157895 x[1] = -0.0526316 x[2] = 3.10526 */ private: array_2(double) A; array_2(double) L; array_2(double) U; array_1(double) b; array_1(int) p; array_1(double) x; array_1(double) y; public: CLinearEqualtion(int n) { assert(n>1); A = array_2(double)(n); L = array_2(double)(n); U = array_2(double)(n); for (int i= 0; i < n;i++) { A[i] = array_1(double)(n); L[i] = array_1(double)(n); U[i] = array_1(double)(n); } b = array_1(double)(n); x = array_1(double)(n); y = array_1(double)(n); p = array_1(int)(n); } // !CLinearEqualtion(int n) virtual ~CLinearEqualtion(){} // !virtual ~CLinearEqualtion() public: void init_A(array_2(double) _A) { for (int i = 0; i < _A.size(); i++) A[i].assign(_A[i].begin(), _A[i].end()); } // !void init_A(array_2(double) _A) void init_A(std::string _fileName) { std::ifstream in(_fileName.c_str()); int i = 0; int j = 0; while(!in.eof()) { double e = 0; in>>e; std::cout<<e<<std::endl; A[i][j] = e; if (j==A.size() - 1) { i++; j = 0; } else { j++; } } } // !void init_A(std::string _fileName) void init_b(std::string _fileName) { std::ifstream in(_fileName.c_str()); int i = 0; while(!in.eof()) { double e = 0; in>>e; std::cout<<e<<std::endl; b[i++] = e; } } // !void init_b(std::string _fileName) void lu_decomposition() { int n = A.size(); // get array size for (int i = 0; i < n; i++) p[i] = i; for (int k = 0; k < n; k++) { int max = 0; int k_ = k; // get max e in col k. for (int i = k; i < n; i++) { if (fabs(A[i][k]) > max) { max = fabs(A[i][k]); k_ = i; } } // make sure not all is zero. if (max == 0) assert("singular matrix"); // swap cur row,max row. if (k != k_) { swap(p[k], p[k_]); for (int i = 0; i < n; i++) swap(A[k][i], A[k_][i]); } for (int i = k + 1; i < n; i++) { // gen v A[i][k] /= A[k][k]; for (int j = k + 1; j < n; j++) { A[i][j] -= A[i][k] * A[k][j]; } } } init_LU(); } // !void lu_decomposition() void init_LU() { int n = A.size(); // get array size for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (i > j) { L[i][j] = A[i][j]; } else { U[i][j] = A[i][j]; if (i == j) L[i][i] = 1; } } } } // !void init_LU() void lup_solve() { int n = A.size(); int i = 0, j = 0; for (i = 0; i < n; i++) { x[i] = 0; y[i] = 0; } for (i = 0; i < n; i++) { y[i] = b[p[i]]; for (j = 0; j < i; j++) y[i] -= L[i][j] * y[j]; } for (i = n - 1; i >= 0; i--) { double delt = y[i]; for (j = n - 1; j > i; j--) delt -= U[i][j] * x[j]; x[i] = delt / U[i][j]; } } // !void lup_solve() void show_y() { int n = A.size(); std::cout << "###" << std::endl; for (int i = 0; i < n; i++) { std::cout << "y[" << i << "]=" << y[i] << std::endl; } } // !void show_y() void show_x() { int n = A.size(); std::cout << "###" << std::endl; for (int i = 0; i < n; i++) std::cout << "x[" << i << "]=" << x[i] << std::endl; } // !void show_x() void save_solution() { int n = A.size(); ofstream out("result.txt", ios::out); out << "-------------------------------------" << std::endl; std::cout << "-------------------------------------" << std::endl; for (int i = 0; i < n; i++) { out << "x[" << i << "] = " << x[i]<< std::endl; std::cout << "x[" << i << "] = " << x[i]<< std::endl; } out << "-------------------------------------" << std::endl; std::cout << "-------------------------------------" << std::endl; out.close(); } }; }
鏈接:http://pan.baidu.com/s/1hqJes4k 密碼:elwz