行列の固有値(フレーム法+ベアストウ法)

#*******************************************/
# 行列の固有値(フレーム法+ベアストウ法) */
#      coded by Y.Suganuma                 */
#*******************************************/

#************************************************/
# 行列の固有値(フレーム法+ベアストウ法)      */
#      n : 次数                                 */
#      ct : 最大繰り返し回数                    */
#      eps : 収束判定条件                       */
#      p0, q0 : x2+px+qにおけるp,qの初期値      */
#      a : 係数(最高次から与え,値は変化する) */
#      b, c : 作業域((n+1)次の配列)           */
#      rl, im : 結果の実部と虚部                */
#      aa : 行列                                */
#      h1, h2 : 作業域(nxnの行列)             */
#      return : =0 : 正常                       */
#               =1 : 収束せず                   */
#      coded by Y.Suganuma                      */
#************************************************/
def Frame(n, ct, eps, p0, q0, a, b, c, rl, im, aa, h1, h2)
	a[0] = 1.0
					# a1の計算
	a[1] = 0.0
	for i1 in 0 ... n
		a[1] -= aa[i1][i1]
	end
					# a2の計算
	for i1 in 0 ... n
		for i2 in 0 ... n
			h1[i1][i2] = aa[i1][i2]
		end
		h1[i1][i1] += a[1]
	end

	a[2] = 0.0
	for i1 in 0 ... n
		for i2 in 0 ... n
			a[2] -= aa[i1][i2] * h1[i2][i1]
		end
	end
	a[2] *= 0.5
					# a3からanの計算
	for i1 in 3 ... n+1

		for i2 in 0 ... n
			for i3 in 0 ... n
				h2[i2][i3] = 0.0
				for i4 in 0 ... n
					h2[i2][i3] += aa[i2][i4] * h1[i4][i3]
				end
			end
			h2[i2][i2] += a[i1-1]
		end

		a[i1] = 0.0
		for i2 in 0 ... n
			for i3 in 0 ... n
				a[i1] -= aa[i2][i3] * h2[i3][i2]
			end
		end
		a[i1] /= i1

		for i2 in 0 ... n
			for i3 in 0 ... n
				h1[i2][i3] = h2[i2][i3]
			end
		end
	end
					# ベアストウ法
	ind = Bairstow(n, ct, eps, p0, q0, a, b, c, rl, im, 0)

	return ind
end

#************************************************/
# 実係数代数方程式の解(ベアストウ法)          */
#      n : 次数                                 */
#      ct : 最大繰り返し回数                    */
#      eps : 収束判定条件                       */
#      p0, q0 : x2+px+qにおけるp,qの初期値      */
#      a : 係数(最高次から与え,値は変化する) */
#      b,c : 作業域((n+1)次の配列)            */
#      rl, im : 結果の実部と虚部                */
#      k : 結果の位置                           */
#      return : =0 : 正常                       */
#               =1 : 収束せず                   */
#      coded by Y.Suganuma                      */
#************************************************/
def Bairstow(n, ct, eps, p0, q0, a, b, c, rl, im, k)
			# 初期設定
	p1    = p0
	p2    = 0.0
	q1    = q0
	q2    = 0.0
	ind   = 0
	count = 0
#
#          1次の場合
#
	if n == 1
		if a[0].abs() < eps
			ind = 1
		else
			rl[k] = -a[1] / a[0]
			im[k] = 0.0
		end
#
#          2次の場合
#
	elsif n == 2
					# 1次式
		if a[0].abs() < eps
			if a[1].abs() < eps
				ind = 1
			else
				rl[k] = -a[2] / a[1]
				im[k] = 0.0
			end
					# 2次式
		else
			d = a[1] * a[1] - 4.0 * a[0] * a[2]
			if d < 0.0   # 虚数
				d        = Math.sqrt(-d)
				a[0]    *= 2.0
				rl[k]    = -a[1] / a[0]
				rl[k+1]  = -a[1] / a[0]
				im[k]    = d / a[0]
				im[k+1]  = -im[0]
			else           # 実数
				d       = Math.sqrt(d)
				a[0]    = 1.0 / (2.0 * a[0])
				rl[k]   = a[0] * (-a[1] + d)
				rl[k+1] = a[0] * (-a[1] - d)
				im[k]   = 0.0
				im[k+1] = 0.0
			end
		end
					# 3次以上の場合
	else
						# 因数分解
		ind = 1
		while ind > 0 && count <= ct
			for i1 in 0 ... n+1
				if i1 == 0
					b[i1] = a[i1]
				elsif i1 == 1
					b[i1] = a[i1] - p1 * b[i1-1]
				else
					b[i1] = a[i1] - p1 * b[i1-1] - q1 * b[i1-2]
				end
			end
			for i1 in 0 ... n+1
				if i1 == 0
					c[i1] = b[i1]
				elsif i1 == 1
					c[i1] = b[i1] - p1 * c[i1-1]
				else
					c[i1] = b[i1] - p1 * c[i1-1] - q1 * c[i1-2]
				end
			end
			d = c[n-2] * c[n-2] - c[n-3] * (c[n-1] - b[n-1])
			if d.abs() < eps
				return ind
			else
				dp = (b[n-1] * c[n-2] - b[n] * c[n-3]) / d
				dq = (b[n] * c[n-2] - b[n-1] * (c[n-1] - b[n-1])) / d
				p2 = p1 + dp
				q2 = q1 + dq
				if dp.abs() < eps && dq.abs() < eps
					ind = 0
				else
					count += 1
					p1 = p2
					q1 = q2
				end
			end
		end

		if ind == 0
						# 2次方程式を解く
			d = p2 * p2 - 4.0 * q2
			if d < 0.0   # 虚数
				d       = Math.sqrt(-d)
				rl[k]   = -0.5 * p2
				rl[k+1] = -0.5 * p2
				im[k]   = 0.5 * d
				im[k+1] = -im[k]
			else           # 実数
				d       = Math.sqrt(d)
				rl[k]   = 0.5 * (-p2 + d)
				rl[k+1] = 0.5 * (-p2 - d)
				im[k]   = 0.0
				im[k+1] = 0.0
			end
						# 残りの方程式を解く
			n -= 2
			for i1 in 0 ... n+1
				a[i1] = b[i1]
			end
			ind = Bairstow(n, ct, eps, p0, q0, a, b, c, rl, im, k+2)
		end
	end

	return ind
end

					# データの設定
ct   = 1000
eps  = 1.0e-10
p0   = 0.0
q0   = 0.0
n    = 3
a    = Array.new(n+1)
b    = Array.new(n+1)
c    = Array.new(n+1)
rl   = Array.new(n)
im   = Array.new(n)
aa   = Array.new(n)
h1   = Array.new(n)
h2   = Array.new(n)
for i1 in 0 ... n
	aa[i1] = Array.new(n)
	h1[i1] = Array.new(n)
	h2[i1] = Array.new(n)
end

aa[0][0] = 7.0
aa[0][1] = 2.0
aa[0][2] = 1.0

aa[1][0] = 2.0
aa[1][1] = 1.0
aa[1][2] = -4.0

aa[2][0] = 1.0
aa[2][1] = -4.0
aa[2][2] = 2.0
				# 計算
ind = Frame(n, ct, eps, p0, q0, a, b, c, rl, im, aa, h1, h2)
				# 出力
if ind > 0
	printf("収束しませんでした!\n")
else
	for i1 in 0 ... n
		printf("   %f  i %f\n", rl[i1], im[i1])
	end
end