<?php /************************************************/ /* 実対称行列の固有値・固有ベクトル(ヤコビ法) */ /* coded by Y.Suganuma */ /************************************************/ // データの設定 $ct = 1000; $eps = 1.0e-10; $n = 3; $A = array($n); $A1 = array($n); $A2 = array($n); $X1 = array($n); $X2 = array($n); for ($i1 = 0; $i1 < $n; $i1++) { $A[$i1] = array($n); $A1[$i1] = array($n); $A2[$i1] = array($n); $X1[$i1] = array($n); $X2[$i1] = array($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"); } } /*************************************************************/ /* 実対称行列の固有値・固有ベクトル(ヤコビ法) */ /* n : 次数 */ /* ct : 最大繰り返し回数 */ /* eps : 収束判定条件 */ /* A : 対象とする行列 */ /* A1, A2 : 作業域(nxnの行列),A1の対角要素が固有値 */ /* X1, X2 : 作業域(nxnの行列),X1の各列が固有ベクトル */ /* return : =0 : 正常 */ /* =1 : 収束せず */ /* coded by Y.Suganuma */ /*************************************************************/ function Jacobi($n, $ct, $eps, $A, &$A1, $A2, &$X1, $X2) { // 初期設定 $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 (abs($A1[$i1][$i2]) > $max) { $max = abs($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 = abs($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; } ?>