C++寫矩陣求逆

systemvue是一款專用的雷達,通信仿真軟件,其底層的封裝的模塊庫是用c++寫的。


聽博士哥哥說該軟件目前處於推廣階段,由於目前模塊庫匱乏,所以比較蛋疼,就在這蛋疼的時候,我導師接到了這塊燙手的山芋,然後更蛋疼的是,把這個寫庫的任務分給了我。。。。於是乎我又重拾C++大法,被迫暫停大數據比賽(我的穿衣搭配啊大哭),全力轉到寫庫上面來。最近接到博士哥哥的一個任務,讓我寫一個矩陣求逆的模塊,給systemvue用。不管怎麼樣,寫起來再說。

#include <iostream>

.......

然後怎麼辦。。。

腦子裏面搜索着矩陣求逆的算法,想到以前本科老師講過有個克萊默算法,求矩陣的逆的,先求矩陣的行列式,然後按照公式套一下,這是第一種方法。然後想到了算法導論上面貌似有矩陣運算的討論,打開一開果然有大笑。第28章都是關於矩陣運算的,有求解線性方程的問題,有矩陣求逆的問題,也有對稱正定矩陣和最小二乘逼近 。

上面講的大致算法是通過將矩陣求逆運算轉換成線性方程求解問題,比如求A矩陣的逆,AX=E,E爲單位陣,X(i)爲X的第i列,e(i)爲E的第i列,有A*X(i) = e(i)。X爲A的逆矩陣,寫到這些相信大家明白了,A的逆矩陣X即爲n個方程的解組成的,換句話說這n個解是X矩陣的列向量。至於怎麼求解線性方程組,算法導論提供了一種LUP分解的方法。

LUP分解:找三個n*n矩陣L,U和P,滿足PA=LU,P爲置換矩陣,講A = P(逆)LU,在求解Ax=b時,兩邊同乘以P,即得LUx=Pb,L爲下三角矩陣,U爲上三角矩陣,x可以通過簡單的循環過程求出。該算法的關鍵點在於找到LUP這三個矩陣。具體的矩陣求解過程在這裏就不詳細說明了,有興趣的同學可以在算法導論上仔細研讀。

下面貼下我的C++代碼。由於好久沒有寫過C++代碼了,所以寫的並不是很好,數組定義應該用vector容器,不應該定長,而且就算定長也不應該用魔數來寫,起碼定義const int 常量。這裏各位不要學不負責任的我,壞壞的說一句,要是輸入模塊的矩陣維數超過100的話,我的程序就要出錯了。。。。偷笑

類聲明:

#include <iostream>
#include <cstdio>

class Matrix{
public:
	Matrix();
	~Matrix();
	int get_size() const;
	void inverse();
	void show() const;
	void initialize();
	void lupDecomposition(int (*p)[100], double (*left)[100], double (*up)[100]);

private:
	double data[100][100];
	int rowsize, colsize;
	double* lupSolve(double (*left)[100], double (*up)[100], int *position, double *b);
};
類函數定義:

#include "Matrix.h"

Matrix::Matrix()
{
	rowsize = 3;
	colsize = 3;
	for (int i = 0; i < rowsize; i++) 
		for (int j = 0; j < colsize; j++) {
			data[i][j] = (i + j ) * j + 1;
		}	
}

Matrix::~Matrix()
{
}

void Matrix::initialize()
{
	using namespace std;
	int myrowsize = 0,	mycolsize = 0;
	cout << "input the size of Matrix (row, col) : " << endl;
	cin >> myrowsize >> mycolsize;
	rowsize = myrowsize;
	colsize = mycolsize;
	cout << "input the value of Matrix !" << endl;
	for (int i = 0; i < myrowsize; i++) 
		for (int j = 0; j < mycolsize; j++) {
			cin >> data[i][j];
		}
}

void Matrix::show() const
{
	printf("the rowsize is %d, the colsize is %d\n", rowsize, colsize);
	for (int i = 0; i < rowsize; i++) {
		for (int j = 0; j < colsize; j++)
			printf("%f ", data[i][j]);
		printf("\n");
	}
}

int Matrix::get_size() const
{
	return colsize;
}

void Matrix::lupDecomposition(int (*p)[100], double (*left)[100], double (*up)[100])
{
	int n = get_size();
	int position[100] = {0};

	//初始化position數組
	for (int i = 0; i < n; i++) {
		position[i] = i;
	}

	//定義矩陣a, 並且賦值
	double a[100][100] = {0};
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			a[i][j] = data[i][j];

	for (int k = 0; k < n; k++) {
		double max_row_data = -100000;
		int max_row = k;
		for (int i = k; i < n; i++) {
			if (abs(a[i][k]) > max_row_data) {
				max_row_data = abs(a[i][k]);
				max_row = i;
			}
		}

		if (max_row_data == 0) { 
			printf("this Matrix is singular!");
			return;
		}

		int tmp = 0;
		tmp = position[k];
		position[k] = position[max_row];
		position[max_row] = tmp;

		for (int i = 0; i < n; i++) {
			double tmp = 0;
			tmp = a[k][i];
			a[k][i] = a[max_row][i];
			a[max_row][i] = tmp;
		}

		for (int i = k+1; i < n; i++) {
			a[i][k] /= a[k][k];
			for (int j = k+1; j < n; j++)
				a[i][j] -= a[i][k]*a[k][j];
		}
	}

	//給矩陣P賦值
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++) {
			if (j == position[i])
				p[i][j] = 1;
			else
				p[i][j] = 0;
		}

	//給矩陣left賦值
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++) {
			if (i == j)
				left[i][j] = 1;
			else if (i > j)
				left[i][j] = a[i][j];
			else
				left[i][j] = 0;
		}

	//給矩陣up賦值
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++) {
			if (i <= j)
				up[i][j] = a[i][j];
			else
				up[i][j] = 0;
		}

}


double* Matrix::lupSolve(double (*left)[100], double (*up)[100], int *position, double *b)
{
	int n = get_size();
	double x[100] = {0};
	double y[100] = {0};

	for (int i = 0; i < n; i++) {
		double partSum = 0;
		for (int j = 0; j <= i-1; j++)
			partSum += left[i][j]*y[j];
		y[i] = b[position[i]] - partSum;
	}

	for (int i = n-1; i >= 0; i--) {
		double partSum = 0;
		for (int j = i+1; j <= n-1; j++)
			partSum += up[i][j] * x[j];
		x[i] = (y[i] - partSum) / up[i][i];
	}
	return x;
}

void Matrix::inverse()
{
	double left[100][100] = {{1, 0, 0}, {0.2, 1, 0}, {0.6, 0.5, 1}};
	double up[100][100] = {{5, 6, 3}, {0, 0.8, -0.6}, {0, 0, 2.5}};
	int position[100] = {2, 0, 1};
	int p[100][100] = {0};

	/*double *x;
	x = lupSolve(left, up, position, b);
	for (int i = 0; i < 3; i++)
		printf("%f ", x[i]);*/

	lupDecomposition(p, left, up);

	//得到position,和得到單位矩陣額e[n][n]
	int n = get_size();
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			if (p[i][j] == 1)
				position[i] = j;
	double e[100][100] = {0};
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			if (i == j)
				e[i][j] = 1;
			else
				e[i][j] = 0;

	//構造逆矩陣
	double result[100][100] = {0};
	for (int i = 0; i < n; i++) {
		double *x = NULL;
		x = lupSolve(left, up, position, e[i]);
		for (int j = 0; j < n; j++)
			result[j][i] = x[j];
	}

	//打印result數組
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++)
			printf("%f ", result[i][j]);
		printf("\n");
	}

	return;
}
                                   


發佈了65 篇原創文章 · 獲贊 75 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章