最大固有値と固有ベクトル(べき乗法)

<?php

/****************************************/
/* 最大固有値と固有ベクトル(べき乗法) */
/*      coded by Y.Suganuma             */
/****************************************/

					// データの設定
	$ct  = 200;
	$eps = 1.0e-10;
	$n   = 3;
	$m   = 15;

	$A   = array($n);
	$B   = array($n);
	$C   = array($n);
	$v   = array($n);
	for ($i1 = 0; $i1 < $n; $i1++) {
		$A[$i1] = array($n);
		$B[$i1] = array($n);
		$C[$i1] = array($n);
		$v[$i1] = array($n);
	}

	$r  = array($n);
	$v0 = array($n);
	$v1 = array($n);
	$v2 = array($n);

	$A[0][0] = 11.0;
	$A[0][1] = 6.0;
	$A[0][2] = -2.0;

	$A[1][0] = -2.0;
	$A[1][1] = 18.0;
	$A[1][2] = 1.0;

	$A[2][0] = -12.0;
	$A[2][1] = 24.0;
	$A[2][2] = 13.0;

	for ($i1 = 0; $i1 < $n; $i1++) {
		for ($i2 = 0; $i2 < $n; $i2++)
			$B[$i1][$i2] = 0.0;
		$B[$i1][$i1] = 1.0;
		$v0[$i1]     = 1.0;
	}
					// 計算
	$ind = power(0, $n, $m, $ct, $eps, $A, $B, $C, $r, $v, $v0, $v1, $v2);
					// 出力
	if ($ind == 0)
		printf("固有値が求まりませんでした!\n");
	else {
		for ($i1 = 0; $i1 < $ind; $i1++) {
			printf("固有値 %f", $r[$i1]);
			printf(" 固有ベクトル ");
			for ($i2 = 0; $i2 < $n; $i2++)
				printf(" %f", $v[$i1][$i2]);
			printf("\n");
		}
	}

/****************************************/
/* 最大固有値と固有ベクトル(べき乗法) */
/*      i : 何番目の固有値かを示す      */
/*      n : 次数                        */
/*      m : 丸め誤差の修正回数          */
/*      ct : 最大繰り返し回数           */
/*      eps : 収束判定条件              */
/*      A : 対象とする行列              */
/*      B : nxnの行列,最初は,単位行列 */
/*      C : 作業域,nxnの行列           */
/*      r : 固有値                      */
/*      v : 各行が固有ベクトル(nxn)   */
/*      v0 : 固有ベクトルの初期値       */
/*      v1,v2 : 作業域(n次元ベクトル) */
/*      return : 求まった固有値の数     */
/*      coded by Y.Suganuma             */
/****************************************/
function power($i, $n, $m, $ct, $eps, $A, $B, $C, &$r, &$v, $v0, $v1, $v2)
{
					// 初期設定
	$ind = $i;
	$k   = 0;
	$l1  = 0.0;
	for ($i1 = 0; $i1 < $n; $i1++) {
		$l1      += $v0[$i1] * $v0[$i1];
		$v1[$i1]  = $v0[$i1];
	}
	$l1 = sqrt($l1);
					// 繰り返し計算
	while ($k < $ct) {
						// 丸め誤差の修正
		if ($k%$m == 0) {
			$l2 = 0.0;
			for ($i1 = 0; $i1 < $n; $i1++) {
				$v2[$i1] = 0.0;
				for ($i2 = 0; $i2 < $n; $i2++)
					$v2[$i1] += $B[$i1][$i2] * $v1[$i2];
				$l2 += $v2[$i1] * $v2[$i1];
			}
			$l2 = sqrt($l2);
			for ($i1 = 0; $i1 < $n; $i1++)
				$v1[$i1] = $v2[$i1] / $l2;
		}
						// 次の近似
		$l2 = 0.0;
		for ($i1 = 0; $i1 < $n; $i1++) {
			$v2[$i1] = 0.0;
			for ($i2 = 0; $i2 < $n; $i2++)
				$v2[$i1] += $A[$i1][$i2] * $v1[$i2];
			$l2 += $v2[$i1] * $v2[$i1];
		}
		$l2 = sqrt($l2);
		for ($i1 = 0; $i1 < $n; $i1++)
			$v2[$i1] /= $l2;
						// 収束判定
							// 収束した場合
		if (abs(($l2-$l1)/$l1) < $eps) {
			$k1 = -1;
			for ($i1 = 0; $i1 < $n && $k1 < 0; $i1++) {
				if (abs($v2[$i1]) > 0.001) {
					$k1 = $i1;
					if ($v2[$k1]*$v1[$k1] < 0.0)
						$l2 = -$l2;
				}
			}
			$k     = $ct;
			$r[$i] = $l2;
			for ($i1 = 0; $i1 < $n; $i1++)
				$v[$i][$i1] = $v2[$i1];
			if ($i == $n-1)
				$ind = $i + 1;
			else {
				for ($i1 = 0; $i1 < $n; $i1++) {
					for ($i2 = 0; $i2 < $n; $i2++) {
						$C[$i1][$i2] = 0.0;
						for ($i3 = 0; $i3 < $n; $i3++) {
							$x            = ($i1 == $i3) ? $A[$i1][$i3] - $l2 : $A[$i1][$i3];
							$C[$i1][$i2] += $x * $B[$i3][$i2];
						}
					}
				}
				for ($i1 = 0; $i1 < $n; $i1++) {
					for ($i2 = 0; $i2 < $n; $i2++)
						$B[$i1][$i2] = $C[$i1][$i2];
				}
				for ($i1 = 0; $i1 < $n; $i1++) {
					$v1[$i1] = 0.0;
					for ($i2 = 0; $i2 < $n; $i2++)
						$v1[$i1] += $B[$i1][$i2] * $v0[$i2];
				}
				for ($i1 = 0; $i1 < $n; $i1++)
					$v0[$i1] = $v1[$i1];
				$ind = power($i+1, $n, $m, $ct, $eps, $A, $B, $C, $r, $v, $v0, $v1, $v2);
			}
		}
							// 収束しない場合
		else {
			for ($i1 = 0; $i1 < $n; $i1++)
				$v1[$i1] = $v2[$i1];
			$l1 = $l2;
			$k++;
		}
	}

	return $ind;
}

?>