#*************************************/ # シンプレックス法による最小値の計算 */ # coded by Y.Suganuma */ #*************************************/ #******************/ # 関数値の計算 */ # y = f(x) */ # return : y */ #******************/ # 関数1 snx1 = Proc.new { |x| x1 = x[0] - 1.0 y1 = x[1] - 2.0 x1 * x1 + y1 * y1 } # 関数2 snx2 = Proc.new { |x| x1 = x[1] - x[0] * x[0] y1 = 1.0 - x[0] 100.0 * x1 * x1 + y1 * y1 } # 関数3 snx3 = Proc.new { |x| x1 = 1.5 - x[0] * (1.0 - x[1]) y1 = 2.25 - x[0] * (1.0 - x[1] * x[1]) z1 = 2.625 - x[0] * (1.0 - x[1] * x[1] * x[1]) x1 * x1 + y1 * y1 + z1 * z1 } #*****************************************/ # シンプレックス法 */ # max : 最大繰り返し回数 */ # n : 次元 */ # k : 初期値設定係数 */ # r1 : 縮小比率 */ # r2 : 拡大比率 */ # y : 最小値 */ # x : x(初期値と答え) */ # snx : 関数値を計算する関数名 */ # return : >=0 : 正常終了(収束回数) */ # =-1 : 収束せず */ #*****************************************/ def simplex(max, n, k, eps, r1, r2, y, x, &snx) # 初期値の設定 fh = -1 fg = -1 fl = -1 count = 0 sw = -1 yy = Array.new(n+1) xg = Array.new(n) xr = Array.new(n) xn = Array.new(n) xx = Array.new(n+1) for i1 in 0 ... n+1 xx[i1] = Array.new(n) end for i1 in 0 ... n+1 for i2 in 0 ... n xx[i1][i2] = x[i2] end if i1 > 0 xx[i1][i1-1] += k end yy[i1] = snx.call(xx[i1]) end # 最大値,最小値の計算 for i1 in 0 ... n+1 if fh < 0 || yy[i1] > yy[fh] fh = i1 end if fl < 0 || yy[i1] < yy[fl] fl = i1 end end for i1 in 0 ... n+1 if i1 != fh && (fg < 0 || yy[i1] > yy[fg]) fg = i1 end end # 最小値の計算 while count < max && sw < 0 count += 1 # 重心の計算 for i1 in 0 ... n xg[i1] = 0.0 end for i1 in 0 ... n+1 if i1 != fh for i2 in 0 ... n xg[i2] += xx[i1][i2] end end end for i1 in 0 ... n xg[i1] /= n end # 最大点の置き換え for i1 in 0 ... n xr[i1] = 2.0 * xg[i1] - xx[fh][i1] end yr = snx.call(xr) if yr >= yy[fh] # 縮小 for i1 in 0 ... n xr[i1] = (1.0 - r1) * xx[fh][i1] + r1 * xr[i1] end yr = snx.call(xr) elsif yr < (yy[fl]+(r2-1.0)*yy[fh])/r2 # 拡大 for i1 in 0 ... n xn[i1] = r2 * xr[i1] - (r2 - 1.0) * xx[fh][i1] end yn = snx.call(xn) if yn <= yr for i1 in 0 ... n xr[i1] = xn[i1] end yr = yn end end for i1 in 0 ... n xx[fh][i1] = xr[i1] end yy[fh] = yr # シンプレックス全体の縮小 if yy[fh] >= yy[fg] for i1 in 0 ... n+1 if i1 != fl for i2 in 0 ... n xx[i1][i2] = 0.5 * (xx[i1][i2] + xx[fl][i2]) end yy[i1] = snx.call(xx[i1]) end end end # 最大値,最小値の計算 fh = -1 fg = -1 fl = -1 for i1 in 0 ... n+1 if fh < 0 || yy[i1] > yy[fh] fh = i1 end if fl < 0 || yy[i1] < yy[fl] fl = i1 end end for i1 in 0 ... n+1 if i1 != fh && (fg < 0 || yy[i1] > yy[fg]) fg = i1 end end # 収束判定 e = 0.0 for i1 in 0 ... n+1 if i1 != fl yr = yy[i1] - yy[fl] e += yr * yr end end if e < eps sw = 0 end end if sw == 0 sw = count y[0] = yy[fl] for i1 in 0 ... n x[i1] = xx[fl][i1] end end return sw end # データの入力 sw = 0 str = gets() a = str.split(" ") fun = Integer(a[1]) n = Integer(a[3]) max = Integer(a[5]) k = Float(a[7]) str = gets(); a = str.split(" "); eps = Float(a[1]) r1 = Float(a[3]) r2 = Float(a[5]) x = Array.new(n) y = Array.new(1) sw = 0 str = gets(); a = str.split(" "); for i1 in 0 ... n x[i1] = Float(a[i1+1]) end # 実行 case fun when 1 sw = simplex(max, n, k, eps, r1, r2, y, x, &snx1) when 2 sw = simplex(max, n, k, eps, r1, r2, y, x, &snx2) when 3 sw = simplex(max, n, k, eps, r1, r2, y, x, &snx3) end # 結果の出力 if sw < 0 printf(" 収束しませんでした!") else printf(" 結果=") for i1 in 0 ... n printf("%f ", x[i1]) end printf(" 最小値=%f 回数=%d\n", y[0], sw) end