# -*- coding: UTF-8 -*- from math import * import numpy as np ############################################ # Newton法による非線形方程式(f(x)=0)の解 # fn : f(x)を計算する関数名 # dfn : f(x)の微分を計算する関数名 # x0 : 初期値 # eps1 : 終了条件1(|x(k+1)-x(k)|<eps1) # eps2 : 終了条件2(|f(x(k))|<eps2) # max : 最大試行回数 # w : f(x)の微分の逆行列を入れる (n x 2n) # n : xの次数 # x : 解 # return : 実際の試行回数 # (負の時は解を得ることができなかった) # coded by Y.Suganuma ############################################ def newton(fn, dfn, x0, eps1, eps2, max, w, n, x) : ind = 0 sw = 0 g = np.empty(n, np.float) x1 = np.empty(n, np.float) for i1 in range(0, n) : x1[i1] = x0[i1] x[i1] = x1[i1] while sw == 0 and ind >= 0 : sw = 1 ind += 1 fn(x1, g) sw1 = 0 for i1 in range(0, n) : if abs(g[i1]) > eps2 : sw1 = 1 break if sw1 > 0 : if ind <= max : sw1 = dfn(x1, w, eps2) if sw1 == 0 : for i1 in range(0, n) : x[i1] = x1[i1] for i2 in range(0, n) : x[i1] -= w[i1][i2+n] * g[i2] sw1 = 0 for i1 in range(0, n) : if abs(x[i1]-x1[i1]) > eps1 and abs(x[i1]-x1[i1]) > eps1*abs(x[i1]) : sw1 = 1 break if sw1 > 0 : for i1 in range(0, n) : x1[i1] = x[i1] sw = 0 else : ind = -1 else : ind = -1 return ind ############################################ # 線形連立方程式を解く(逆行列を求める) # w : 方程式の左辺及び右辺 # n : 方程式の数 # m : 方程式の右辺の列の数 # eps : 逆行列の存在を判定する規準 # return : =0 : 正常 # =1 : 逆行列が存在しない # coded by Y.Suganuma ############################################ def gauss(w, n, m, eps) : nm = n + m; ind = 0 for i1 in range(0, n) : y1 = 0.0 m1 = i1 + 1 m2 = 0 # ピボット要素の選択 for i2 in range(i1, n) : y2 = abs(w[i2][i1]) if y1 < y2 : y1 = y2 m2 = i2 # 逆行列が存在しない if y1 < eps : ind = 1 break # 逆行列が存在する else : # 行の入れ替え for i2 in range(i1, nm) : y1 = w[i1][i2] w[i1][i2] = w[m2][i2] w[m2][i2] = y1 # 掃き出し操作 y1 = 1.0 / w[i1][i1] for i2 in range(m1, nm) : w[i1][i2] *= y1 for i2 in range(0, n) : if i2 != i1 : for i3 in range(m1, nm) : w[i2][i3] -= (w[i2][i1] * w[i1][i3]) return ind ---------------------------------- # -*- coding: UTF-8 -*- import numpy as np from math import * from function import newton, gauss ############################################ # 多次元ニュートン法 # (3点(0.5,1.0),(0.0,1.5),(0.5,2.0) # を通る円の中心と半径) # coded by Y.Suganuma ############################################ # 関数値(f(x))の計算 def snx(x, y) : y[0] = (0.5 - x[0]) * (0.5 - x[0]) + (1.0 - x[1]) * (1.0 - x[1]) - x[2] * x[2]; y[1] = (0.0 - x[0]) * (0.0 - x[0]) + (1.5 - x[1]) * (1.5 - x[1]) - x[2] * x[2]; y[2] = (0.5 - x[0]) * (0.5 - x[0]) + (2.0 - x[1]) * (2.0 - x[1]) - x[2] * x[2]; # 関数の微分の計算 # x : 変数値 # w : 微分の逆行列(後半) # eps : 逆行列の存在を判定する規準 # return : =0 : 正常 # =1 : 逆行列が存在しない def dsnx(x, w, eps) : for i1 in range(0, 3) : for i2 in range(0, 3) : w[i1][i2+3] = 0.0 w[i1][i1+3] = 1.0 w[0][0] = -2.0 * (0.5 - x[0]) w[0][1] = -2.0 * (1.0 - x[1]) w[0][2] = -2.0 * x[2] w[1][0] = -2.0 * (0.0 - x[0]) w[1][1] = -2.0 * (1.5 - x[1]) w[1][2] = -2.0 * x[2] w[2][0] = -2.0 * (0.5 - x[0]) w[2][1] = -2.0 * (2.0 - x[1]) w[2][2] = -2.0 * x[2] sw = gauss(w, 3, 3, eps) return sw # データの設定 eps1 = 1.0e-7 eps2 = 1.0e-10 max = 20 n = 3 x = np.array([0, 0, 0], np.float) x0 = np.array([0, 0, 2], np.float) w = np.empty((n, 2*n), np.float) # 実行と結果 ind = newton(snx, dsnx, x0, eps1, eps2, max, w, n, x) print("ind = " + str(ind)) print("x " + str(x[0]) + " " + str(x[1]) + " " + str(x[2])) snx(x, x0) print("f " + str(x0[0]) + " " + str(x0[1]) + " " + str(x0[2]))