0. Выберем начальное приближение ; k = 0;
1. Вычисляем k-е приближение к собственному значению λm+1:
; (3.42)
2. Находим вектор из уравнения
; (3.43)
3. Если m > 0 ортогонализируем вектор к первым m собственным векторам
(3.44)
4. Нормируем полученный вектор
(3.45)
5. k = k + 1;
Процесс 1. —5. повторяется до тех пор, пока не будет выполнено условие сходимости итераций
, (3.46)
где ε – заданная погрешность.
При вычислении первого собственного значения и соответствующего вектора пункт 3) пропускается.
Этим алгоритмом можно вычислить все собственные значения и собственные векторы.
Пример 3.11. Найти все собственные значения и соответствующие собственные векторы матриц:
1).
Решение с помощью программы на языке C++. Реализуем алгоритм (3.42) — (3.46) на языке C++ и проверим программу на данном примере, сравнивая полученный результат с ответами из примеров 3.9, 3.10.
Текст программы приведен ниже:
#include <iostream.h>
#include <except.h>
#include <stdlib.h>
#include <math.h>
int Eigen(long double **a, long double **x, long double *eigv,
long double eps, const int n, int k_max);
long double s_prod(long double *x1, long double *x2, const int n);
int gauss(long double **a, long double *b, long double *x, const int n);
int main(){
long double **a, **x, *eigv, eps; int i,j,n,k_max;
cout <<" input n = " ; cin >> n;
cout <<" input k_max = " ; cin >> k_max;
cout <<" input eps = " ; cin >> eps;
try {
a = new long double*[n]; for(i=0;i<n;i++) a[i]=new long double[n];
x = new long double*[n]; for(i=0;i<n;i++) x[i]=new long double[n];
eigv = new long double[n];
}
catch (xalloc){cout <<" Could not allocate "; exit(-1);}
cout <<" input matrix a: ";
for (i=0; i<n; i++)for (j=0; j<n; j++)cin >> a[i][j];
cout <<" matrix a:";
for (i=0; i<n; i++){
cout << " ";for (j=0; j<n; j++)cout <<" "<< a[i][j];}
Eigen(a, x, eigv, eps, n, k_max);
for(i = 0; i < n; i++)cout << " Eigen Value [" << i << "] = " << eigv[i];
cout << " Eigen Vectors: " ;
for (i=0; i<n; i++){
cout <<" "; for (j=0; j<n; j++) cout << " " << x[i][j];}
cout <<" ";
cin >> i; // for pause
for(i = 0; i < n; i++) delete[] a[i];
delete a;
for(i = 0; i < n; i++) delete[] x[i];
delete x;
delete[] eigv;
return 0;
}//end main --------------------------------------------------------------
int Eigen(long double **a, long double **x, long double *eigv,
long double eps, const int n, int k_max){
int i, j, k, m;
long double **a1,*x0,*x1,*alf, xerr, xnrm, eig0, eig1,s;
a1 = new long double*[n]; for(i=0;i<n;i++) a1[i]=new long double[n];
x0 = new long double[n]; x1 = new long double[n];
alf = new long double[n];
for(m = 0; m < n; m++){
// 0.
k = 0; for(i = 0; i < n; i++)x0[i] = 1. ; eig0 = 0;
do {
// 1.
for(i = 0; i < n; i++){s = 0;
for(j = 0; j < n; j++)s += a[i][j]*x0[j]; x1[i] = s;}
eig1 = s_prod(x1,x0,n)/s_prod(x0,x0,n);
// 2.
for(i = 0; i < n; i++)x1[i] = eig1*x0[i];
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)a1[i][j] = a[i][j];
gauss(a1,x1,x0,n);
// 3.
if(m > 0){
for(j = 0; j < m ; j++){
for(i = 0; i < n; i++)x1[i] = x[i][j];
alf[j] = s_prod(x0,x1,n)/s_prod(x1,x1,n);
}
for(i = 0; i < n; i++)
for(j = 0; j < m; j++)x0[i]= x0[i] - x[i][j]*alf[j];
}// end if
// 4.
xnrm = sqrt(s_prod(x0,x0,n));
for(i = 0; i < n; i++)x0[i] = x0[i] / xnrm;
xerr = fabs(eig1 - eig0); eig0 = eig1;
k = k + 1; if (k > k_max)break;
}while (xerr > eps);
eigv[m] = eig1;
for(i = 0; i < n; i++) x[i][m] = x0[i];
}// end m
for(i = 0; i < n; i++) delete[] a1[i];
delete a1;
delete[] x0;
delete[] x1;
delete[] alf;
return 0;
}// end Eigen
long double s_prod(long double *x1, long double *x2, const int n){
long double s; int i; s = 0;
for(i = 0; i < n; i++)s = s + x1[i]*x2[i];
return s;
}// end s_prod
int gauss(long double **a, long double *b, long double *x, const int n){
int i, k, m; long double amm, aim;
for (m = 0; m <= n-2; m++) {// m
amm = a[m][m];
for (k = m; k <= n-1; k++)a[m][k] = a[m][k]/amm; // 3.16
b[m] = b[m] / amm; //
for (i = m + 1; i <= n-1; i++){// i
aim = a[i][m];
for (k = m; k <= n-1; k++)
a[i][k] = a[i][k] - a[m][k]*aim; // 3.17
b[i] = b[i] - b[m]*aim; //
}// end i
}// end m
x[n-1] = b[n-1]/a[n-1][n-1]; // 3.19
for (i = n - 2; i >= 0; i--){// i
x[i] = b[i]; //
for (k = i + 1; k < n; k++) // 3.20
x[i] = x[i] - a[i][k]*x[k]; //
}// end i
return 0;
}// end gauss
Приведем результаты расчетов:
1) Для матрицы A:
Input n = 3
Input k_max = 100
Input eps = 0.001
Input matrix a:
3 1 0 1 2 0 0 0 2
matrix a:
3 1 0
1 2 0
0 0 2
Eigen Value [0] = 1.38279
Eigen Value [1] = 1.99985
Eigen Value [2] = 3.61796
Eigen Vectors:
-0.525551 0.0189405 0.850551
0.850389 -0.0179017 0.52585
0.0251862 0.99966 -0.00669857
2) Для матрицы B:
Input n = 4
Input k_max = 1000
Input eps = 0.0000001
Input matrix a:
5 -1 0 0 -1 7 4 1 0 4 8 3 0 1 3 7
matrix a:
5 -1 0 0
-1 7 4 1
0 4 8 3
0 1 3 7
Eigen Value [0] = 2.79088
Eigen Value [1] = 4.87123
Eigen Value [2] = 6.31445
Eigen Value [3] = 13.0234
Eigen Vectors:
0.279353 0.861671 0.41803 -0.0688165
0.617008 0.110771 -0.549768 0.552074
-0.660456 0.261569 0.018022 0.703602
0.324131 -0.420517 0.722967 0.442067
Приведем для дополнительной проверки правильности работы программы результаты расчета собственных значений и собственных векторов я матрицы B в программе Mathcad:
Сравнив эти результаты, можно сделать вывод о корректности работы программы и правильности алгоритма (3.42) — (3.46).
Замечание.Так как программа носит учебный характер, интерфейс программы сделан простым, достаточным на наш взгляд для понимания алгоритма. В частности, если размерность матрицы больше четырех, то вывод матрицы на экран может быть не таким наглядным (строка матрицы может не поместиться в одну строку экрана). В этом случае студентам предлагается изменить программу в соответствующей части.