シンプレックス法

#*************************************/
# シンプレックス法による最小値の計算 */
#      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