Nathan Shin
08-01-2010, 03:08 AM
Hello,
I took the Jacobi routine from the book "Numerical Recipes in C (page 467-468)" to obatin eigenvalues and corresponding eigenvectors from a real symmetric matrix.
There are no compilation errors, but the program does not produce correct eigenvalues and eigenvectors. It's completely wrong.
Given a real symmetric matrix is
5.0 -2.0
-2.0 2.0
The eigenvalues and eigenvectors generated by the program are
0.000000
2.000000
and
0.000000 0.000000
0.000000 1.000000
Actually, the program produces same eigenvectors regardless of what a given symmetric matrix is. Also, it always produces the last element of a given symmetric matrix instead of eigenvalues.
I already checked several times.
That means, the program really does not work.
Would you tell me what I need to fix the routine?
<IMPORTANT>
Followings are main program constructed by myself and a subroutine taken from the book "Numerical Recipes" respectively.
************* main program *************
#include <stdio.h>
/*declare global variables */
float a[2][2]={5.0,-2.0,-2.0,2.0};
float d[2];
float v[2][2];
int n=2;
int nrot=0;
void jacobi(float (*a)[2],int n, float* d,
float (*v)[2], int *nrot);
int main(void)
{
int x=0;
int y=0;
jacobi(a,n,d,v,&nrot);
for(x=0;x<2;x++)
{
printf("%lf \n",d[x]);
//returns the eigenvalues of a
}
printf("\n");
for(x=0;x<2;x++)
{
for(y=0;y<2;y++)
{
printf("%lf",v[x][y]);
/ / returns the eigenvectors of a
}
return 0;
}
***** subroutine (refer to page 467-468)*****
#include <math.h>
#include "nrutil.h"
#define ROTATE(a,i,j,k,l) g=a[i][j];h=a[k][l];a[i][j]=g-s*(h+g*tau);\
a[k][l]=h+s*(g-h*tau);
void jacobi(float (*a)[2], int n, float* d, float (*v)[2], int *nrot)
{
int j,iq,ip,i;
float tresh,theta,tau,t,sm,s,h,g,c,*b,*z;
b=vector(1,n);
z=vector(1,n);
for (ip=1;ip<=n;ip++) {
for (iq=1;iq<=n;iq++) v[ip][iq]=0.0;
v[ip][ip]=1.0;
}
for (ip=1;ip<=n;ip++)
{
b[ip]=d[ip]=a[ip][ip];
z[ip]=0.0;
}
*nrot=0;
for (i=1;i<=50;i++) {
sm=0.0;
for (ip=1;ip<=n-1;ip++) {
for (iq=ip+1;iq<=n;iq++)
sm += fabs(a[ip][iq]);
}
if (sm == 0.0) {
free_vector(z,1,n);
free_vector(b,1,n);
return;
}
if (i < 4)
tresh=0.2*sm/(n*n);
else
tresh=0.0;
for (ip=1;ip<=n-1;ip++) {
for (iq=ip+1;iq<=n;iq++) {
g=100.0*fabs(a[ip][iq]);
if (i > 4 && (float)(fabs(d[ip])+g) == (float)fabs(d[ip])
&& (float)(fabs(d[iq])+g) == (float)fabs(d[iq]))
a[ip][iq]=0.0;
else if (fabs(a[ip][iq]) > tresh) {
h=d[iq]-d[ip];
if ((float)(fabs(h)+g) == (float)fabs(h))
t=(a[ip][iq])/h;
else {
theta=0.5*h/(a[ip][iq]);
t=1.0/(fabs(theta)+sqrt(1.0+theta*theta));
if (theta < 0.0) t = -t;
}
c=1.0/sqrt(1+t*t);
s=t*c;
tau=s/(1.0+c);
h=t*a[ip][iq];
z[ip] -= h;
z[iq] += h;
d[ip] -= h;
d[iq] += h;
a[ip][iq]=0.0;
for (j=1;j<=ip-1;j++) {
ROTATE(a,j,ip,j,iq)
}
for (j=ip+1;j<=iq-1;j++) {
ROTATE(a,ip,j,j,iq)
}
for (j=iq+1;j<=n;j++) {
ROTATE(a,ip,j,iq,j)
}
for (j=1;j<=n;j++) {
ROTATE(v,j,ip,j,iq)
}
++(*nrot);
}
}
}
for (ip=1;ip<=n;ip++) {
b[ip] += z[ip];
d[ip]=b[ip];
z[ip]=0.0;
}
}
nrerror("Too many iterations in routine jacobi");
}
I took the Jacobi routine from the book "Numerical Recipes in C (page 467-468)" to obatin eigenvalues and corresponding eigenvectors from a real symmetric matrix.
There are no compilation errors, but the program does not produce correct eigenvalues and eigenvectors. It's completely wrong.
Given a real symmetric matrix is
5.0 -2.0
-2.0 2.0
The eigenvalues and eigenvectors generated by the program are
0.000000
2.000000
and
0.000000 0.000000
0.000000 1.000000
Actually, the program produces same eigenvectors regardless of what a given symmetric matrix is. Also, it always produces the last element of a given symmetric matrix instead of eigenvalues.
I already checked several times.
That means, the program really does not work.
Would you tell me what I need to fix the routine?
<IMPORTANT>
Followings are main program constructed by myself and a subroutine taken from the book "Numerical Recipes" respectively.
************* main program *************
#include <stdio.h>
/*declare global variables */
float a[2][2]={5.0,-2.0,-2.0,2.0};
float d[2];
float v[2][2];
int n=2;
int nrot=0;
void jacobi(float (*a)[2],int n, float* d,
float (*v)[2], int *nrot);
int main(void)
{
int x=0;
int y=0;
jacobi(a,n,d,v,&nrot);
for(x=0;x<2;x++)
{
printf("%lf \n",d[x]);
//returns the eigenvalues of a
}
printf("\n");
for(x=0;x<2;x++)
{
for(y=0;y<2;y++)
{
printf("%lf",v[x][y]);
/ / returns the eigenvectors of a
}
return 0;
}
***** subroutine (refer to page 467-468)*****
#include <math.h>
#include "nrutil.h"
#define ROTATE(a,i,j,k,l) g=a[i][j];h=a[k][l];a[i][j]=g-s*(h+g*tau);\
a[k][l]=h+s*(g-h*tau);
void jacobi(float (*a)[2], int n, float* d, float (*v)[2], int *nrot)
{
int j,iq,ip,i;
float tresh,theta,tau,t,sm,s,h,g,c,*b,*z;
b=vector(1,n);
z=vector(1,n);
for (ip=1;ip<=n;ip++) {
for (iq=1;iq<=n;iq++) v[ip][iq]=0.0;
v[ip][ip]=1.0;
}
for (ip=1;ip<=n;ip++)
{
b[ip]=d[ip]=a[ip][ip];
z[ip]=0.0;
}
*nrot=0;
for (i=1;i<=50;i++) {
sm=0.0;
for (ip=1;ip<=n-1;ip++) {
for (iq=ip+1;iq<=n;iq++)
sm += fabs(a[ip][iq]);
}
if (sm == 0.0) {
free_vector(z,1,n);
free_vector(b,1,n);
return;
}
if (i < 4)
tresh=0.2*sm/(n*n);
else
tresh=0.0;
for (ip=1;ip<=n-1;ip++) {
for (iq=ip+1;iq<=n;iq++) {
g=100.0*fabs(a[ip][iq]);
if (i > 4 && (float)(fabs(d[ip])+g) == (float)fabs(d[ip])
&& (float)(fabs(d[iq])+g) == (float)fabs(d[iq]))
a[ip][iq]=0.0;
else if (fabs(a[ip][iq]) > tresh) {
h=d[iq]-d[ip];
if ((float)(fabs(h)+g) == (float)fabs(h))
t=(a[ip][iq])/h;
else {
theta=0.5*h/(a[ip][iq]);
t=1.0/(fabs(theta)+sqrt(1.0+theta*theta));
if (theta < 0.0) t = -t;
}
c=1.0/sqrt(1+t*t);
s=t*c;
tau=s/(1.0+c);
h=t*a[ip][iq];
z[ip] -= h;
z[iq] += h;
d[ip] -= h;
d[iq] += h;
a[ip][iq]=0.0;
for (j=1;j<=ip-1;j++) {
ROTATE(a,j,ip,j,iq)
}
for (j=ip+1;j<=iq-1;j++) {
ROTATE(a,ip,j,j,iq)
}
for (j=iq+1;j<=n;j++) {
ROTATE(a,ip,j,iq,j)
}
for (j=1;j<=n;j++) {
ROTATE(v,j,ip,j,iq)
}
++(*nrot);
}
}
}
for (ip=1;ip<=n;ip++) {
b[ip] += z[ip];
d[ip]=b[ip];
z[ip]=0.0;
}
}
nrerror("Too many iterations in routine jacobi");
}