余白の書きなぐり

aueweのブログ

C言語からLAPACKのzheevを呼んでエルミート行列を対角化

昔書いた記事のコメントでzheevの使い方を書けと言われた。 なので書いた。僕は優しいなあ。 こういうのは他人が書いた記事を鵜呑みにするより、zheev.fでググってヒットする一次情報を見るほうがいいと思うよ。 Fortranが分からなくても普通に読めると思う。 僕(を含めた一般ユーザー)の解説は往々にして間違ってるわけで、過信するのはこわいいいい

/*
 * SIZE*SIZE型のエルミート行列の固有値と固有ベクトルを計算
 *  (1  -2i)
 *  (+2i 1)
 */

#include <stdio.h>
#include <complex.h>
#define SIZE 2

int main(void) {
// 複素行列(エルミート)の対角化 (入力行列の配列は対角化後にユニタリ行列になる)
  char   jobz = 'V'           ;// 固有ベクトルを計算する
  char   uplo = 'U'           ;// Aに上三角行列を格納
  int    n    = SIZE          ;// 対角化する正方行列のサイズ

  double _Complex A[SIZE*SIZE];// 対角化する行列。対角化後は固有ベクトルが並ぶ
  A[0]=1; A[2]=-2*I;
  A[1]=2*I; A[3]=1;

  double w[SIZE]              ;// 実固有値が小さい順に入る

  int    lda  = SIZE          ;// 対角化する正方行列のサイズ
  double _Complex work[6*SIZE];// 対角化する際に使用するメモリ
  int    lwork = 6*SIZE       ;// workの次元
  double rwork[3*SIZE-2]      ;// 3*SIZE-2で固定
  int    info                 ;// 成功すれば0、失敗すれば0以外を返す

  zheev_( &jobz, &uplo, &n, A, &lda, w, work, &lwork, rwork, &info );
  // 1番目の固有値 : w[0]  1番目の固有ベクトル : (A[0] A[1])
  // 2番目の固有値 : w[1]  2番目の固有ベクトル : (A[2] A[3])

  printf("1番目の固有値:%5.3lf\n",w[0]);
  printf("1番目の固有ベクトル:(%5.3lf %+5.3lf*I %5.3lf %+5.3lf*I)\n",
      creal(A[0]), cimag(A[0]), creal(A[1]), cimag(A[1]));

  printf("1番目の固有値:%5.3lf\n",w[1]);
  printf("2番目の固有ベクトル:(%5.3lf %+5.3lf*I %5.3lf %+5.3lf*I)\n",
      creal(A[2]), cimag(A[2]), creal(A[3]), cimag(A[3]));

  return 0;
}

コンパイルと実行結果

$ gcc hoge.c -lm -lblas -llapack
$ ./a.out
1番目の固有値:-1.000
1番目の固有ベクトル:(0.000 +0.707*I 0.707 +0.000*I)
1番目の固有値:3.000
2番目の固有ベクトル:(0.000 -0.707*I 0.707 +0.000*I)