/************************************************/ /* 実対称行列の固有値・固有ベクトル(ヤコビ法) */ /* coded by Y.Suganuma */ /************************************************/ #include <stdio.h> int Jacobi(int, int, double, double **, double **, double **, double **, double **); int main() { double **A, **A1, **A2, **X1, **X2, eps; int i1, i2, ind, ct, n; // データの設定 ct = 1000; eps = 1.0e-10; n = 3; A = new double * [n]; A1 = new double * [n]; A2 = new double * [n]; X1 = new double * [n]; X2 = new double * [n]; for (i1 = 0; i1 < n; i1++) { A[i1] = new double [n]; A1[i1] = new double [n]; A2[i1] = new double [n]; X1[i1] = new double [n]; X2[i1] = new double [n]; } A[0][0] = 1.0; A[0][1] = 0.0; A[0][2] = -1.0; A[1][0] = 0.0; A[1][1] = 1.0; A[1][2] = -1.0; A[2][0] = -1.0; A[2][1] = -1.0; A[2][2] = 2.0; // 計算 ind = Jacobi(n, ct, eps, A, A1, A2, X1, X2); // 出力 if (ind > 0) printf("収束しませんでした!\n"); else { printf("固有値\n"); for (i1 = 0; i1 < n; i1++) printf(" %f", A1[i1][i1]); printf("\n固有ベクトル(各列が固有ベクトル)\n"); for (i1 = 0; i1 < n; i1++) { for (i2 = 0; i2 < n; i2++) printf(" %f", X1[i1][i2]); printf("\n"); } } for (i1 = 0; i1 < n; i1++) { delete [] A[i1]; delete [] A1[i1]; delete [] A2[i1]; delete [] X1[i1]; delete [] X2[i1]; } delete [] A; delete [] A1; delete [] A2; delete [] X1; delete [] X2; return 0; } /*************************************************************/ /* 実対称行列の固有値・固有ベクトル(ヤコビ法) */ /* n : 次数 */ /* ct : 最大繰り返し回数 */ /* eps : 収束判定条件 */ /* A : 対象とする行列 */ /* A1, A2 : 作業域(nxnの行列),A1の対角要素が固有値 */ /* X1, X2 : 作業域(nxnの行列),X1の各列が固有ベクトル */ /* return : =0 : 正常 */ /* =1 : 収束せず */ /* coded by Y.Suganuma */ /*************************************************************/ #include <math.h> int Jacobi(int n, int ct, double eps, double **A, double **A1, double **A2, double **X1, double **X2) { double max, s, t, v, sn, cs; int i1, i2, k = 0, ind = 1, p = 0, q = 0; // 初期設定 for (i1 = 0; i1 < n; i1++) { for (i2 = 0; i2 < n; i2++) { A1[i1][i2] = A[i1][i2]; X1[i1][i2] = 0.0; } X1[i1][i1] = 1.0; } // 計算 while (ind > 0 && k < ct) { // 最大要素の探索 max = 0.0; for (i1 = 0; i1 < n; i1++) { for (i2 = 0; i2 < n; i2++) { if (i2 != i1) { if (fabs(A1[i1][i2]) > max) { max = fabs(A1[i1][i2]); p = i1; q = i2; } } } } // 収束判定 // 収束した if (max < eps) ind = 0; // 収束しない else { // 準備 s = -A1[p][q]; t = 0.5 * (A1[p][p] - A1[q][q]); v = fabs(t) / sqrt(s * s + t * t); sn = sqrt(0.5 * (1.0 - v)); if (s*t < 0.0) sn = -sn; cs = sqrt(1.0 - sn * sn); // Akの計算 for (i1 = 0; i1 < n; i1++) { if (i1 == p) { for (i2 = 0; i2 < n; i2++) { if (i2 == p) A2[p][p] = A1[p][p] * cs * cs + A1[q][q] * sn * sn - 2.0 * A1[p][q] * sn * cs; else if (i2 == q) A2[p][q] = 0.0; else A2[p][i2] = A1[p][i2] * cs - A1[q][i2] * sn; } } else if (i1 == q) { for (i2 = 0; i2 < n; i2++) { if (i2 == q) A2[q][q] = A1[p][p] * sn * sn + A1[q][q] * cs * cs + 2.0 * A1[p][q] * sn * cs; else if (i2 == p) A2[q][p] = 0.0; else A2[q][i2] = A1[q][i2] * cs + A1[p][i2] * sn; } } else { for (i2 = 0; i2 < n; i2++) { if (i2 == p) A2[i1][p] = A1[i1][p] * cs - A1[i1][q] * sn; else if (i2 == q) A2[i1][q] = A1[i1][q] * cs + A1[i1][p] * sn; else A2[i1][i2] = A1[i1][i2]; } } } // Xkの計算 for (i1 = 0; i1 < n; i1++) { for (i2 = 0; i2 < n; i2++) { if (i2 == p) X2[i1][p] = X1[i1][p] * cs - X1[i1][q] * sn; else if (i2 == q) X2[i1][q] = X1[i1][q] * cs + X1[i1][p] * sn; else X2[i1][i2] = X1[i1][i2]; } } // 次のステップへ k++; for (i1 = 0; i1 < n; i1++) { for (i2 = 0; i2 < n; i2++) { A1[i1][i2] = A2[i1][i2]; X1[i1][i2] = X2[i1][i2]; } } } } return ind; }