Jacobi algorithm for eigenvalues and eigenvectors

purpose

Seeking a real symmetric matrix of all the eigenvalues ​​and eigenvectors.

Pre-knowledge

For a real symmetric matrix \ (A \) diagonal matrix, there must be \ (D \) and orthogonal matrix \ (the U-\) satisfies \ [D = the TAU the U-^ \] \ (D \) diagonal elements is \ (a \) eigenvalues, \ (the U-\) column vector as \ (a \) feature vectors.

定义\(n\)阶旋转矩阵\[G(p,q,\theta)= \begin{bmatrix} 1 & & & & & \cdots& & & & & 0\\ &\ddots & & & & & & & & &\\ & &1 & & & & & & & &\\ & & &\cos\theta & & & &-\sin\theta & & &\\ & & & &1 & &0 & & & &\\ & & & & &\ddots & & & & &\\ & & & &0 & &1 & & & &\\ & & &\sin\theta & & & &\cos\theta & & &\\ & & & & & & & &1 & &\\ & & & & & & & & &\ddots &\\ 0& & & & & & & &0 & &1 \ end {bmatrix} \] )\ (a_ {pp} = a_that is the basis of a unit matrix, the modify

For \ (n-\) order vectors \ (\ Alpha \) , \ (\ Alpha \ CDOT G (P, Q, \ Theta) \) geometric meaning is to \ (\ Alpha \) in the first \ (P \ ) dimensional coordinate axes and \ (Q \) rotating in a plane parallel to the axis of the angle-dimensional coordinate \ (\ Theta \) , and the length of the rotated mold remains unchanged.

Algorithm theory

Probably thinking that the rotation conversion by making the off-diagonal elements on increasingly smaller, and finally obtain the original matrix similar to a diagonal matrix.

Found each matrix \ (A \) the maximum absolute value of the off-diagonal element is set to \ (PQ A_ {} \) , so \ (the U-G = (P, Q, \ Theta) \) , the \ (A \) is converted into \ (U ^ TAU \)

Is converted

By causing \ (b_ {p, q} = 0 \) solving for \ [\ theta = \ frac { 1} {2} \ arctan \ frac {2a_ {pq}} {a_ {qq} -a_ {pp}} \] especially when \ (a_ {qq} = a_ {pp} \) when \ (\ theta = \ frac { \ pi} {4} \)

Noting rotational operation mode does not change the duration of each row or column vector, i.e. matrix \ (A \) of F- norm \ (|| A || _F = \ sqrt {\ sum_i \ sum_ja_ {ij} } ^ 2 \) is constant, and can be obtained by calculating \ [b_ {ip} ^ 2 + b_ {iq} ^ 2 = a_ {ip} ^ 2 + a_ {iq} ^ 2 \] can be obtained known non-diagonal elements of the square and smaller, and the square of the diagonal elements is increased, so that the square and non-convergence on the main diagonal elements.

Algorithmic process

(1) Let matrix \ (T = E \) , i.e., initialization matrix

(2) find \ (A \) the maximum absolute value of non-diagonal elements selected from the group \ (a_ {pq} \)

(3) to find the corresponding angle \ (\ Theta \) , construction of matrix \ (U = G (p, q, \ theta) \)

(4)令\ (A = U ^ year, TU = T \)

(5) continuously repeating (2) through (4) until \ (a_ {pq} <\ epsilon \) , or the number of iterations exceeds a defined value, \ (A \) is approximately equal to the diagonal elements \ (a \) eigenvalues, \ (T \) column vector as \ (a \) eigenvectors

Code

#include<bits/stdc++.h>
using namespace std;

const int N=1005;
const double eps=1e-5;
const int lim=100;

int n,id[N];
double key[N],mat[N][N],EigVal[N],EigVec[N][N],tmpEigVec[N][N];

bool cmpEigVal(int x,int y)
{
    return key[x]>key[y];
}

void Find_Eigen(int n,double (*a)[N],double *EigVal,double (*EigVec)[N])
{
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
            EigVec[i][j]=0;
    for (int i=1;i<=n;i++) EigVec[i][i]=1.0;
    int count=0;
    while (1)
    {
        //统计迭代次数 
        count++;
        //找绝对值最大的元素 
        double mx_val=0;
        int row_id,col_id;
        for (int i=1;i<n;i++)
            for (int j=i+1;j<=n;j++)
                if (fabs(a[i][j])>mx_val) mx_val=fabs(a[i][j]),row_id=i,col_id=j;
        if (mx_val<eps||count>lim) break;
        //进行旋转变换 
        int p=row_id,q=col_id;
        double Apq=a[p][q],App=a[p][p],Aqq=a[q][q];
        double theta=0.5*atan2(-2.0*Apq,Aqq-App);
        double sint=sin(theta),cost=cos(theta); 
        double sin2t=sin(2.0*theta),cos2t=cos(2.0*theta);
        a[p][p]=App*cost*cost+Aqq*sint*sint+2.0*Apq*cost*sint;
        a[q][q]=App*sint*sint+Aqq*cost*cost-2.0*Apq*cost*sint;
        a[p][q]=a[q][p]=0.5*(Aqq-App)*sin2t+Apq*cos2t;
        for (int i=1;i<=n;i++)
            if (i!=p&&i!=q)
            {
                double u=a[p][i],v=a[q][i];
                a[p][i]=u*cost+v*sint;a[q][i]=v*cost-u*sint;
                u=a[i][p],v=a[i][q];
                a[i][p]=u*cost+v*sint;a[i][q]=v*cost-u*sint;
            }
        //计算特征向量 
        for (int i=1;i<=n;i++)
        {
            double u=EigVec[i][p],v=EigVec[i][q];
            EigVec[i][p]=u*cost+v*sint;EigVec[i][q]=v*cost-u*sint;
        }
    }
    //对特征值排序 
    for (int i=1;i<=n;i++) id[i]=i,key[i]=a[i][i];
    std::sort(id+1,id+n+1,cmpEigVal);
    for (int i=1;i<=n;i++)
    {
        EigVal[i]=a[id[i]][id[i]];
        for (int j=1;j<=n;j++)
            tmpEigVec[j][i]=EigVec[j][id[i]];
    }
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
            EigVec[i][j]=tmpEigVec[i][j];
    //特征向量为列向量 
}

int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
            scanf("%lf",&mat[i][j]);
    Find_Eigen(n,mat,EigVal,EigVec);
    printf("EigenValues = ");
    for (int i=1;i<=n;i++) printf("%lf ",EigVal[i]);
    printf("\nEigenVector =\n");
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
            printf("%lf%c",EigVec[i][j],j==n?'\n':' ');
    return 0;
}

Guess you like

Origin www.cnblogs.com/beginend/p/11749230.html