# -*- coding: UTF-8 -*-
from math import *
import numpy as np
############################################
# 行列の固有値(フレーム法+ベアストウ法)
# n : 次数
# ct : 最大繰り返し回数
# eps : 収束判定条件
# p0, q0 : x2+px+qにおけるp,qの初期値
# a : 係数(最高次から与え,値は変化する)
# b, c : 作業域((n+1)次の配列)
# r : 結果
# A : 行列
# H1, H2 : 作業域(nxnの行列)
# return : =0 : 正常
# =1 : 収束せず
# coded by Y.Suganuma
############################################
def Frame(n, ct, eps, p0, q0, a, b, c, r, A, H1, H2) :
a[0] = 1.0
# a1の計算
a[1] = 0.0
for i1 in range(0, n) :
a[1] -= A[i1][i1]
# a2の計算
for i1 in range(0, n) :
for i2 in range(0, n) :
H1[i1][i2] = A[i1][i2]
H1[i1][i1] += a[1]
a[2] = 0.0
for i1 in range(0, n) :
for i2 in range(0, n) :
a[2] -= A[i1][i2] * H1[i2][i1]
a[2] *= 0.5
# a3からanの計算
for i1 in range(3, n+1) :
for i2 in range(0, n) :
for i3 in range(0, n) :
H2[i2][i3] = 0.0
for i4 in range(0, n) :
H2[i2][i3] += A[i2][i4] * H1[i4][i3]
H2[i2][i2] += a[i1-1]
a[i1] = 0.0
for i2 in range(0, n) :
for i3 in range(0, n) :
a[i1] -= A[i2][i3] * H2[i3][i2]
a[i1] /= i1
for i2 in range(0, n) :
for i3 in range(0, n) :
H1[i2][i3] = H2[i2][i3]
# ベアストウ法
ind = Bairstow(n, ct, eps, p0, q0, a, b, c, r, 0)
return ind
############################################
# 実係数代数方程式の解(ベアストウ法)
# n : 次数
# ct : 最大繰り返し回数
# eps : 収束判定条件
# p0, q0 : x2+px+qにおけるp,qの初期値
# a : 係数(最高次から与え,値は変化する)
# b,c : 作業域((n+1)次の配列)
# r : 結果
# k : 結果の位置
# return : =0 : 正常
# =1 : 収束せず
# coded by Y.Suganuma
############################################
def Bairstow(n, ct, eps, p0, q0, a, b, c, r, k) :
p1 = p0
p2 = 0.0
q1 = q0
q2 = 0.0
ind = 0
count = 0
# 1次の場合
if n == 1 :
if abs(a[0]) < eps :
ind = 1
else :
r[k] = complex(-a[1] / a[0], 0)
# 2次の場合
elif n == 2 :
# 1次式
if abs(a[0]) < eps :
if abs(a[1]) < eps :
ind = 1
else :
r[k] = complex(-a[2] / a[1], 0)
# 2次式
else :
D = a[1] * a[1] - 4.0 * a[0] * a[2]
if D < 0.0 : # 虚数
D = sqrt(-D)
a[0] *= 2.0
r[k] = complex(-a[1] / a[0], D / a[0])
r[k+1] = complex(-a[1] / a[0], -D / a[0])
else : # 実数
D = sqrt(D)
a[0] = 1.0 / (2.0 * a[0])
r[k] = complex(a[0] * (-a[1] + D), 0)
r[k+1] = complex(a[0] * (-a[1] - D), 0)
# 3次以上の場合
else :
# 因数分解
ind = 1
while ind > 0 and count <= ct :
for i1 in range(0, n+1) :
if i1 == 0 :
b[i1] = a[i1]
elif i1 == 1 :
b[i1] = a[i1] - p1 * b[i1-1]
else :
b[i1] = a[i1] - p1 * b[i1-1] - q1 * b[i1-2]
for i1 in range(0, n+1) :
if i1 == 0 :
c[i1] = b[i1]
elif i1 == 1 :
c[i1] = b[i1] - p1 * c[i1-1]
else :
c[i1] = b[i1] - p1 * c[i1-1] - q1 * c[i1-2]
D = c[n-2] * c[n-2] - c[n-3] * (c[n-1] - b[n-1])
if fabs(D) < 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 abs(dp) < eps and fabs(dq) < eps :
ind = 0
else :
count += 1
p1 = p2
q1 = q2
if ind == 0 :
# 2次方程式を解く
D = p2 * p2 - 4.0 * q2
if D < 0.0 : # 虚数
D = sqrt(-D)
r[k] = complex(-0.5 * p2, 0.5 * D)
r[k+1] = complex(-0.5 * p2, -0.5 * D)
else : # 実数
D = sqrt(D)
r[k] = complex(0.5 * (-p2 + D), 0)
r[k+1] = complex(0.5 * (-p2 - D), 0)
# 残りの方程式を解く
n -= 2
for i1 in range(0, n+1) :
a[i1] = b[i1]
ind = Bairstow(n, ct, eps, p0, q0, a, b, c, r, k+2)
return ind
----------------------------------
# -*- coding: UTF-8 -*-
import numpy as np
from math import *
from function import Bairstow, Frame
############################################
# 行列の固有値(フレーム法+ベアストウ法) */
# coded by Y.Suganuma */
############################################
# データの設定
ct = 1000
eps = 1.0e-10
p0 = 0.0
q0 = 0.0
n = 3
a = np.empty(n+1, np.float)
b = np.empty(n+1, np.float)
c = np.empty(n+1, np.float)
r = np.empty(n, np.complex)
A = np.array([[7, 2, 1],[2, 1, -4],[1, -4, 2]], np.float)
H1 = np.empty((n, n), np.float)
H2 = np.empty((n, n), np.float)
# 計算
ind = Frame(n, ct, eps, p0, q0, a, b, c, r, A, H1, H2)
# 出力
if ind > 0 :
print("収束しませんでした!")
else :
for i1 in range(0, n) :
print(" " + str(r[i1]))