私は固有値と固有ベクトルを広範囲に利用するプログラムを作っています。プログラムをテストしているとき、同じ固有値を持つ2つの固有ベクトルがまったく直交していない場合がありました。縮退した固有ベクトルの場合、その解は一意ではなく、解決ルーチンは特定のベクトルを生成することが保証されていません。縮退した固有ベクトルの線形結合は依然として同じ固有値を持つ固有ベクトルです。しかし、私はそれらの2つが直交することを期待しました。Lapack dgeevは固有ベクトルを非直交に縮退する
これはバグですか? dgeevによって生成されるすべての固有ベクトルは直交であるべきですか?直交ベクトルを常に印刷するルーチンがありますか?
#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;
}
そして、ここで出力されます:ここで
はCでテストケースである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は私に多くの "普通" になります。
*この行列は対称ですが、必ずしもそうではありません。
私はちょうどここのヒップ(私はラップを使用したことはありません)から撃っていますが、浮動小数点の丸めの問題のようです。詳細については、http://stackoverflow.com/questions/588004/is-floating-point-math-brokenを参照してください。 – tonysdg
関連する? http://icl.cs.utk.edu/lapack-forum/viewtopic.php?f=2&t=1769同じ行列に対してJuliaでLAPACK.geev!()を使ってみました。縮退のために非直交固有ベクトルを与えましたペア。 – roygvib
@roygvib、はい、間違いなく助かりました。私はDSYEVDに切り替え、それは直交固有ベクトルを印刷します(ただし、対称行列が必要です)。私は非対称行列が可能かどうかを調べることにしました。なぜなら、それは間違っているかもしれないと思ったからです。 –