実対称行列の固有値・固有ベクトル(ヤコビ法)

#***********************************************/
# 実対称行列の固有値・固有ベクトル(ヤコビ法) */
#      coded by Y.Suganuma                     */
#***********************************************/

#************************************************************/
# 実対称行列の固有値・固有ベクトル(ヤコビ法)              */
#      n : 次数                                             */
#      ct : 最大繰り返し回数                                */
#      eps : 収束判定条件                                   */
#      a : 対象とする行列                                   */
#      a1, a2 : 作業域(nxnの行列),a1の対角要素が固有値   */
#      x1, x2 : 作業域(nxnの行列),x1の各列が固有ベクトル */
#      return : =0 : 正常                                   */
#               =1 : 収束せず                               */
#      coded by Y.Suganuma                                  */
#************************************************************/
def Jacobi(n, ct, eps, a, a1, a2, x1, x2)
					# 初期設定
	k   = 0
	ind = 1
	p   = 0
	q   = 0
	for i1 in 0 ... n
		for i2 in 0 ... n
			a1[i1][i2] = a[i1][i2]
			x1[i1][i2] = 0.0
		end
		x1[i1][i1] = 1.0
	end
					# 計算
	while ind > 0 && k < ct
						# 最大要素の探索
		max = 0.0
		for i1 in 0 ... n
			for i2 in 0 ... n
				if i2 != i1
					if a1[i1][i2].abs() > max
						max = a1[i1][i2].abs()
						p   = i1
						q   = i2
					end
				end
			end
		end
						# 収束判定
							# 収束した
		if max < eps
			ind = 0
							# 収束しない
		else
								# 準備
			s  = -a1[p][q]
			t  = 0.5 * (a1[p][p] - a1[q][q])
			v  = t.abs() / Math.sqrt(s * s + t * t)
			sn = Math.sqrt(0.5 * (1.0 - v))
			if s*t < 0.0
				sn = -sn
			end
			cs = Math.sqrt(1.0 - sn * sn)
								# akの計算
			for i1 in 0 ... n
				if i1 == p
					for i2 in 0 ... n
						if i2 == p
							a2[p][p] = a1[p][p] * cs * cs + a1[q][q] * sn * sn -
                                       2.0 * a1[p][q] * sn * cs
						elsif i2 == q
							a2[p][q] = 0.0
						else
							a2[p][i2] = a1[p][i2] * cs - a1[q][i2] * sn
						end
					end
				elsif i1 == q
					for i2 in 0 ... n
						if (i2 == q)
							a2[q][q] = a1[p][p] * sn * sn + a1[q][q] * cs * cs +
                                       2.0 * a1[p][q] * sn * cs
						elsif i2 == p
							a2[q][p] = 0.0
						else
							a2[q][i2] = a1[q][i2] * cs + a1[p][i2] * sn
						end
					end
				else
					for i2 in 0 ... n
						if i2 == p
							a2[i1][p] = a1[i1][p] * cs - a1[i1][q] * sn
						elsif i2 == q
							a2[i1][q] = a1[i1][q] * cs + a1[i1][p] * sn
						else
							a2[i1][i2] = a1[i1][i2]
						end
					end
				end
			end
								# xkの計算
			for i1 in 0 ... n
				for i2 in 0 ... n
					if i2 == p
						x2[i1][p] = x1[i1][p] * cs - x1[i1][q] * sn
					elsif i2 == q
						x2[i1][q] = x1[i1][q] * cs + x1[i1][p] * sn
					else
						x2[i1][i2] = x1[i1][i2]
					end
				end
			end
								# 次のステップへ
			k += 1
			for i1 in 0 ... n
				for i2 in 0 ... n
					a1[i1][i2] = a2[i1][i2]
					x1[i1][i2] = x2[i1][i2]
				end
			end
		end
	end

	return ind
end

					# データの設定
ct   = 1000
eps  = 1.0e-10
n    = 3
a    = Array.new(n)
a1   = Array.new(n)
a2   = Array.new(n)
x1   = Array.new(n)
x2   = Array.new(n)
for i1 in 0 ... n
	a[i1]  = Array.new(n)
	a1[i1] = Array.new(n)
	a2[i1] = Array.new(n)
	x1[i1] = Array.new(n)
	x2[i1] = Array.new(n)
end

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 in 0 ... n
		printf(" %f", a1[i1][i1])
	end
	printf("\n固有ベクトル(各列が固有ベクトル)\n")
	for i1 in 0 ... n
		for i2 in 0 ... n
			printf(" %f", x1[i1][i2])
		end
		printf("\n")
	end
end