1

I am making a program which makes extensive use of eigenvalues and eigenvectors. While testing the program, I ran into a case where two eigenvectors with the same eigenvalue are not quite orthogonal. I know that in the case of degenerate eigenvectors, the solution is not unique and the solve routine is not guaranteed to produce a certain vector, since a linear combination of the degenerate eigenvectors is still an eigenvector with the same eigenvalue. However, I did expect the two of them to be orthogonal.

Is this a bug? Should all eigenvectors produced by dgeev be orthogonal? Is there another routine that will always print out orthogonal vectors?

Here is a test case in C:

#include <stdio.h>

void ctofortran(double *matrix,double *fortranMatrix,int numberOfRows,int numberOfColumns)
{
/******************************************************************/
/* This function converts a row-major C matrix into a column-major*/
/* fortran "array".                                               */
/******************************************************************/
int columnNumber,rowNumber;
for (columnNumber = 0;columnNumber<numberOfColumns ;columnNumber++ )
{
    for (rowNumber = 0;rowNumber<numberOfRows ;rowNumber++ )
    {
        fortranMatrix[rowNumber+numberOfRows*columnNumber] = *(matrix + columnNumber+numberOfColumns*rowNumber);
    }
}
}


int main(int argc, char **argv)
{
double matrix[] = {4,   -1, 0,  -1, 0,  0,  0,  0,  
                  -1,   4,  -1, 0,  0,  0,  0,  0,  
                   0,   -1, 4,  0,  -1, 0,  0,  0,  
                  -1,   0,  0,  4,  0,  -1, 0,  0,  
                   0,   0,  -1, 0,  4,  0,  0,  -1,     
                   0,   0,  0,  -1, 0,  4,  -1, 0,  
                   0,   0,  0,  0,  0,  -1, 4,  -1,     
                   0,   0,  0,  0,  -1, 0,  -1, 4 };
int rows = 8, columns = 8;
double *fortranmatrix = malloc(rows*columns*sizeof(double));
ctofortran(matrix,fortranmatrix,rows,columns);



char jobvl ='v';
char jobvr = 'n';
//This symbolizes that the left eigenvectors will be found
double *realEigenValues,*imaginaryEigenValues;
realEigenValues = malloc(rows*sizeof(double));
imaginaryEigenValues = malloc(rows*sizeof(double));
double *leftEigenVectors = malloc(rows*columns*sizeof(double));
int lwork = rows * 4;
double *work = malloc(lwork*sizeof(double));
//This allocates workspace to be used by dgeev. The recomended space is 4 times the dimension
int info = 0;//After dgeev info = 0 if the calculation went correctly   


dgeev_(&jobvl,&jobvr,&rows,fortranmatrix,&rows,realEigenValues,imaginaryEigenValues,leftEigenVectors,&rows,NULL,&rows,work,&lwork,&info);

int index;
for(index = 0;index<rows;index++)
printf("Eigenvalue %d %g + %g * i\n",index,*(realEigenValues+index), *(imaginaryEigenValues+index));

int v1 = 1, v6 = 6;
double sum = 0;
printf("\nv1\tv6\n");
for(index = 0;index<rows;index++)
{
printf("%g\t%g\n",*(leftEigenVectors+v1*rows+index),*(leftEigenVectors+v6*rows+index));
sum += *(leftEigenVectors+v1*rows+index) * *(leftEigenVectors+v6*rows+index);
}
printf("\n Dot product between v1 and v6 %g\n",sum);

return 0;

}

And here is the output:

Eigenvalue 0 2 + 0 * i
Eigenvalue 1 2.58579 + 0 * i
Eigenvalue 2 4 + 0 * i
Eigenvalue 3 6 + 0 * i
Eigenvalue 4 5.41421 + 0 * i
Eigenvalue 5 5.41421 + 0 * i
Eigenvalue 6 2.58579 + 0 * i
Eigenvalue 7 4 + 0 * i

v1          v6
-0.499878   0
-0.345657   0.353553
0.0110458   0.5
-0.361278   -0.353553
0.361278    0.353553
-0.0110458  -0.5
0.345657    -0.353553
0.499878    -9.88042e-16

Dot product between v1 and v6 0.0220917

v6 looks more "normal" to me.

*This matrix was symmetric, but it will not always be so.

gsamaras
  • 71,951
  • 46
  • 188
  • 305
Tony Ruth
  • 1,358
  • 8
  • 19
  • I'm just shooting from the hip here (I've never used lapack), but that looks like a floating-point rounding problem to me. See http://stackoverflow.com/questions/588004/is-floating-point-math-broken for more information. – tonysdg Jun 15 '16 at 22:34
  • Related? http://icl.cs.utk.edu/lapack-forum/viewtopic.php?f=2&t=1769 I tried using LAPACK.geev!() in Julia for the same matrix, and it gave non-orthogonal eigenvectors for degenerate pairs. – roygvib Jun 15 '16 at 23:42
  • @roygvib, yes, that definitely helped. I switched to DSYEVD and that does print out orthogonal eigenvectors (but it does require a symmetric matrix). I will investigate whether a nonsymmetric matrix was possible, because I thought it was, but maybe that is wrong. – Tony Ruth Jun 16 '16 at 00:07

1 Answers1

0

Try printing with %lf, like this:

printf("\n Dot product between v1 and v6 %lf\n",sum);

like described here: Scanf/Printf double variable C


If that doesn't help, then I am guessing this is a floating point issue (since their dot product is small).

Community
  • 1
  • 1
gsamaras
  • 71,951
  • 46
  • 188
  • 305