#*******************************************/
# 行列の固有値(フレーム法+ベアストウ法) */
# 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