/*  ヤコビ法による行列固有値の計算 */

 

/*  ---- 近似計算の途中を表示 ----  */

 

#include<stdio.h>

#include<math.h>

#define  N        4

#define  EPSILON  1.0E-4

 

double  a[N][N]={{ 8.00, -0.01,  1.05,  0.02 },

                {-0.01,  3.40,  0.24, -0.10 },

                { 1.05,  0.24,  3.50, -0.03 },

                { 0.02, -0.10, -0.03, -1.50 }};

int    k;

double  t[N][N],u[N][N],x[N][N];

 

void main()

{

    int i,j;

    void jacobi(void);

 

    printf("\n ================= given matrix ================= \n\n");

    for(i=0;i<N;i++)

    {

        for(j=0;j<N;j++)

            printf(" %8.4f",a[i][j]);

        printf("\n");

    }

 

    jacobi();

 

    printf("\n ======== characteristic value of matrix ======== \n\n");

    for(i=0;i<N;i++)

        printf(" %8.4f ",a[i][i]);

    printf("\n\n ======== characteristic vector of matrix ======= \n\n");

    for(j=0;j<N;j++)

    {

        printf("  u%d = (",j+1);

        for(i=0;i<N-1;i++)

            printf(" %8.4f,",u[i][j]);

        printf(" %8.4f )\n\n",u[N-1][j]);

    }

}

 

void jacobi()

{

    int   i,j,m,p,q;

    double xx,aa,amax,sn,cs;

    void  max_det(int *,int *,double *);

    void  calc(int,int,double *,double *);

 

    for(i=0;i<N;i++)

        for(j=0;j<N;j++)

            u[i][j] = 0.0;

    for(i=0;i<N;i++)

            u[i][i] = 1.0;

    max_det(&p,&q,&amax);

 

    printf("\n\n **** iteration for approximation \n\n");

    k = 0;

    do

    {

        calc(p,q,&sn,&cs);

        for(i=0;i<N;i++)

            for(j=0;j<N;j++)

                t[i][j] = 0.0;

        for(i=0;i<N;i++)

                t[i][i] = 1.0;

        t[p][q] = sn; t[q][p] = -sn; t[p][p] = t[q][q] = cs;

        for(i=0;i<N;i++)

            for(j=0;j<N;j++)

           {

                xx = 0.0;

                for(m=0;m<N;m++)

                      xx = xx+a[i][m]*t[m][j];

                x[i][j]= xx;

            }

        for(i=0;i<N;i++)

            for(j=0;j<N;j++)

            {

                aa = 0.0;

                for(m=0;m<N;m++)

                    aa = aa+t[m][i]*x[m][j];

                a[i][j] = aa;

            }

        for(i=0;i<N;i++)

            for(j=0;j<N;j++)

                x[i][j] = u[i][j];

        for(i=0;i<N;i++)

            for(j=0;j<N;j++)

            {

                xx = 0.0;

                for(m=0;m<N;m++)

                    xx = xx+x[i][m]*t[m][j];

                u[i][j] = xx;

            }

        k = k+1;

 

        printf("   #%d   ",k);

        for(i=0;i<N;i++)

        {

            for(j=0;j<N;j++)

                printf(" %8.5f ",a[i][j]);

            printf("\n        ");

        }

        printf("\n");

 

        max_det(&p,&q,&amax);

    }

 

    while(amax > EPSILON);

}

 

void calc(int p,int q,double *sn,double *cs)

{

    double t,tt,absn;

 

    if(a[p][p] != a[q][q])

    {

        t = 2.0*a[p][q]/(a[q][q]-a[p][p]);

        tt = sqrt(t*t+1.0);

        absn = sqrt(0.5*(tt-1.0)/tt);

        if(t>0.0)

            *sn =  absn;

        else

            *sn = -absn;

        *cs = sqrt(0.5*(tt+1.0)/tt);

    }

    else

        *sn = *cs = 0.5*sqrt(2.0);

}

 

void max_det(int *p,int *q,double *amax)

{

    int i,j;

    double absa;

 

    *amax = 0.0;

    for(i=0;i<N-1;i++)

        for(j=i+1

        ;j<N;j++)

        {

            absa = fabs(a[i][j]);

            if(absa > *amax)

            {

                *p = i; *q = j;

                *amax = absa;

            }

        }

}