本系列整理自博主21年秋季学期本科课程 数值分析I 的编程作业,内容相对基础,参考书: David Kincaid, Ward Cheney - Numerical Analysis Mathematics of Scientific Computing (2002, Americal Mathematical Society)
目录
算法引入
考虑矩阵A有如下两条性质:
(i)有唯一一个模最大的特征值。
(ii)n个特征向量线性无关。
设λ1,λ2,…,λn为A的n个特征值,且有
设u1,u2,…,un为对应特征向量,,由线性无关性知{u1,u2,…,un}组成的一组基,任意向量,可表示为
引入迭代:
不妨取,则
由于,所以
设φ为任一线性函数,则,可知比值收敛于λ1:
由此计算矩阵A模最大的特征值λ1,这种方法称为幂法
幂法(Power Method)
这里取向量的无穷范数
辅助部分
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<iomanip>
#include<string.h>
using namespace std;
#define M 60 //maximum iteration step
double InftyNorm(double *x,int n) {
double max = fabs(x[0]);
for (int i = 1; i < n; i++) {
if (fabs(x[i]) > max)
max = fabs(x[i]);
}
return max;
}
void multi(double** A, double* x, double* y, int n) {
//y=Ax
for (int i = 0; i < n; i++) {
y[i] = 0;
for (int j = 0; j < n; j++) {
y[i] += A[i][j] * x[j];
}
}
}
void output(int k, double* x, double r, int n) {
cout << setw(3) << "k=" <<setw(2)<< k << " " << "x(" <<setw(2)<< k << ")=(";
for (int i = 0; i < n; i++) {
cout <<setiosflags(ios::fixed)<<setprecision(9)<< setw(12) << x[i];
if (i < n - 1)
cout << ",";
}
cout << ")";
cout << " r(" << k - 1 << ")=" << r << endl;
}
归一化幂法
void NormalizedPowerMethod(double** A, double* x,int p, int n) {
double *y, r = 0, temp = 0, norm = 1;
y = (double*)malloc(n * sizeof(double));
cout << " Normalized Power Method: " << endl;
cout << setw(3) << "k=" << setw(2) << 0 << " " << "x(" << setw(2) << 0 << ")=(";
for (int i = 0; i < n; i++) {
cout << setiosflags(ios::fixed) << setprecision(9) << setw(13) << x[i];
if (i < n - 1)
cout << ",";
}
cout << ")" << endl;
for (int k = 1; k < M; k++) {
multi(A, x, y, n);
if (x[p] == 0) {
cout << "g(x)=0";//g is a linear function, here g(x)=x_p
return;
}
r = y[p] / x[p];
norm = InftyNorm(y, n);
if (norm == 0) {
cout << "||y||=0";
return;
}
for (int i = 0; i < n; i++)
x[i] = y[i] / norm;
output(k, x, r, n);
if (k > 1)
if(fabs(temp - r) < pow(10, -10))
break;
temp = r;
}
cout << endl;
cout << " The leading eigenvalue of A is " << r << ", and the corresponding eigenvector is (";
for (int i = 0; i < n; i++) {
cout << setiosflags(ios::fixed) << setprecision(5) << setw(8) << x[i];
if (i < n - 1)
cout << ",";
}
cout << ")^T" << endl;
}
逆幂法(Inverse Power Method)
引入
定理 若λ为A的特征值,且A非奇异,则是的特征值
结合幂法,可得出计算A的模最小特征值的方法。
假设A的特征值满足:
则可知A非奇异,的特征值为,满足:
计算A模最小特征值问题,化为计算模最大特征值的方法,对使用幂法即可,迭代形式:
注意:由于矩阵A的维数一般较大,不容易对A求逆,采用对A做LU分解的方法。即由计算问题,化为求解线性方程组的问题,用前述向前迭代算法(forward subsititution or forward iteration)和向后迭代算法(backward subsititution)求解
代码
辅助部分
void Print(double** A, int n) {//print the matrix A with dimension n
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cout <<setw(8)<< A[i][j];
if (j == n - 1) {
cout <<endl;
}
}
}
cout << endl;
}
void DoolittleFactorization(double** A, double** L, double** U, int n) {
//apply Doolittle factorization on A, LU=A
for (int k = 0; k < n; k++) {
if (k == 0) {
for (int j = 0; j < n; j++) {
U[0][j] = A[0][j];//first row of U equals to A's first row
L[j][0] = A[j][0] / U[0][0];//L's first column
}
}
else {
L[k][k] = 1;
for (int i = k; i < n; i++) {
for (int j = 0; j < k; j++) {
U[k][i] += L[k][j] * U[j][i];
if (i + 1 < n) {
L[i + 1][k] += L[i + 1][j] * U[j][k];
}
}
U[k][i] = (A[k][i] - U[k][i]) / L[k][k];
if (i + 1 < n) {
L[i + 1][k] = (A[i + 1][k] - L[i + 1][k]) / U[k][k];
}
}
}
}
cout << " apply Doolitte factorization on A:" << endl;
cout <<setiosflags(ios::fixed) << setprecision(4)<< " L:" << endl;
Print(L, n);
cout << endl;
cout << " U:" << endl;
Print(U, n);
cout << endl;
}
void Solve(double** L, double** U, double* b, double* x, int n) {
//solve linear equations LUx=b
double* z;
z = (double*)malloc(n * sizeof(double));
for (int i = 0; i < n; i++) {//forward subsititution
z[i] = 0;
for (int j = 0; j < i; j++) {
z[i] += L[i][j] * z[j];
}
z[i] = (b[i] - z[i]) / L[i][i];
}
for (int i = n - 1; i >= 0; i--) {//backward subsititution
x[i] = 0;
for (int j = i + 1; j < n; j++) {
x[i] += U[i][j] * x[j];
}
x[i] = (z[i] - x[i]) / U[i][i];
}
}
逆幂法
}
void NormalizedInversePowerMethod(double** A, double* x, int p, int n) {
double** L, ** U;
L = (double**)malloc(n * sizeof(double*));
U = (double**)malloc(n * sizeof(double*));
for (int i = 0; i < n; i++){
L[i]= (double*)malloc(n * sizeof(double));
U[i] = (double*)malloc(n * sizeof(double));
for (int j = 0; j < n; j++) {
L[i][j] = 0;
U[i][j] = 0;
}
}
DoolittleFactorization(A, L, U, n);
double *y, r = 0, temp = 0, norm = 1;
y = (double*)malloc(n * sizeof(double));
for (int i = 0; i < n; i++)
y[i] = 0;
cout << " Normalized Inverse Power Method: " << endl;
cout << setiosflags(ios::right);
cout << setw(3) << "k=" << setw(2) << 0 << " " << "x(" << setw(2) << 0 << ")=(";
for (int i = 0; i < n; i++) {
cout << setiosflags(ios::fixed) << setprecision(9) << setw(13) << x[i];
if (i < n - 1)
cout << ",";
}
cout << ")" << endl;
for (int k = 1; k < M; k++) {
Solve(L, U, x, y, n);//LUy=x
if (x[p] == 0) {
cout << "g(x)=0";//g is a linear function, here g(x)=x_p
return;
}
r = y[p] / x[p];
norm = InftyNorm(y, n);
if (norm == 0) {
cout << "||y||=0";
return;
}
for (int i = 0; i < n; i++)
x[i] = y[i] / norm;
output(k, x, r, n);
if (k > 1)
if (fabs(temp - r) < pow(10, -10))
break;
temp = r;
}
cout << endl;
cout << " The minimum modulus eigenvalue of A is " << 1 / r << ", and the corresponding eigenvector is (";
for (int i = 0; i < n; i++) {
cout << setiosflags(ios::fixed) << setprecision(6) << setw(8) << x[i];
if (i < n - 1)
cout << ",";
}
cout << ")^T" << endl;
}