# -*- coding: UTF-8 -*-
from math import *
import numpy as np
############################################
# 黄金分割法(与えられた方向での最小値)
# a,b : 初期区間 a < b
# eps : 許容誤差
# val : 関数値
# ind : 計算状況
# >= 0 : 正常終了(収束回数)
# = -1 : 収束せず
# max : 最大試行回数
# w : 位置
# dw : 傾きの成分
# snx : 関数値を計算する関数の名前
# return : 結果(w+y*dwのy)
# coded by Y.Suganuma
############################################
def gold(a, b, eps, val, ind, max, w, dw, snx) :
# 初期設定
tau = (sqrt(5.0) - 1.0) / 2.0
x = 0.0
count = 0
ind[0] = -1
x1 = b - tau * (b - a)
x2 = a + tau * (b - a)
f1 = snx(x1, w, dw)
f2 = snx(x2, w, dw)
# 計算
while count < max and ind[0] < 0 :
count += 1
if f2 > f1 :
if abs(b-a) < eps :
ind[0] = 0
x = x1
val[0] = f1
else :
b = x2
x2 = x1
x1 = a + (1.0 - tau) * (b - a)
f2 = f1
f1 = snx(x1, w, dw)
else :
if abs(b-a) < eps :
ind[0] = 0
x = x2
val[0] = f2
f1 = f2
else :
a = x1
x1 = x2
x2 = b - (1.0 - tau) * (b - a)
f1 = f2
f2 = snx(x2, w, dw)
# 収束した場合の処理
if ind[0] == 0 :
ind[0] = count
fa = snx(a, w, dw)
fb = snx(b, w, dw)
if fb < fa :
a = b
fa = fb
if fa < f1 :
x = a
val[0] = fa
return x
############################################
# 共役勾配法
# opt_1 : =0 : 1次元最適化を行わない
# =1 : 1次元最適化を行う
# max : 最大繰り返し回数
# n : 次元
# eps : 収束判定条件
# step : きざみ幅
# y : 最小値
# x : x(初期値と答え)
# dx : 関数の微分値
# snx : 関数値を計算する関数名
# dsnx : 関数の微分を計算する関数名(符号を変える)
# return : >=0 : 正常終了(収束回数)
# =-1 : 収束せず
# =-2 : 1次元最適化の区間が求まらない
# =-3 : 黄金分割法が失敗
############################################
def conjugate(opt_1, max, n, eps, step, y, x, dx, snx, dsnx) :
b = 0.0
s1 = 1.0
count = 0
sw = 0
g = np.empty(n, np.float)
y1 = snx(0.0, x, dx)
y2 = np.empty(1, np.float)
sw1 = np.empty(1, np.int)
while count < max and sw == 0 :
# 傾きの計算
dsnx(x, g)
# 傾きのチェック
s2 = 0.0
for i1 in range(0, n) :
s2 += g[i1] * g[i1]
# 収束していない
if sqrt(s2) > eps :
# 方向の計算
count += 1
if count%n == 1 :
b = 0.0
else :
b = s2 / s1
for i1 in range(0, n) :
dx[i1] = g[i1] + b * dx[i1]
# 1次元最適化を行わない
if opt_1 == 0 :
# 新しい点
for i1 in range(0, n) :
x[i1] += step * dx[i1]
# 新しい関数値
y2[0] = snx(0.0, x, dx)
# 関数値の変化が大きい
if abs(y2[0]-y1) > eps :
y1 = y2[0]
s1 = s2
# 収束(関数値の変化<eps)
else :
sw = count
y[0] = y2[0]
# 1次元最適化を行う
else :
# 区間を決める
sw1[0] = 0
f1 = y1
sp = step
f2 = snx(sp, x, dx)
if f2 > f1 :
sp = -step
for i1 in range(0, max) :
f2 = snx(sp, x, dx)
if f2 > f1 :
sw1[0] = 1
break
else :
sp *= 2.0
f1 = f2
# 区間が求まらない
if sw1[0] == 0 :
sw = -2
# 区間が求まった
else :
# 黄金分割法
k = gold(0.0, sp, eps, y2, sw1, max, x, dx, snx)
# 黄金分割法が失敗
if sw1[0] < 0 :
sw = -3
# 黄金分割法が成功
else :
# 新しい点
for i1 in range(0, n) :
x[i1] += k * dx[i1]
# 関数値の変化が大きい
if abs(y1-y2[0]) > eps :
y1 = y2[0]
s1 = s2
# 収束(関数値の変化<eps)
else :
sw = count
y[0] = y2[0]
# 収束(傾き<eps)
else :
sw = count
y[0] = y1
if sw == 0 :
sw = -1
return sw
----------------------------------
# -*- coding: UTF-8 -*-
import numpy as np
import sys
from math import *
from function import conjugate
############################################
# 共役勾配法による最小値の計算
# coded by Y.Suganuma
############################################
############################################
# 与えられた点xから,dx方向へk*dxだけ進んだ
# 点における関数値を計算する
############################################
# 関数1
def snx1(k, x, dx) :
w = np.empty(2, np.float)
w[0] = x[0] + k * dx[0]
w[1] = x[1] + k * dx[1]
x1 = w[0] - 1.0
y1 = w[1] - 2.0
y = x1 * x1 + y1 * y1
return y
# 関数2
def snx2(k, x, dx) :
w = np.empty(2, np.float)
w[0] = x[0] + k * dx[0]
w[1] = x[1] + k * dx[1]
x1 = w[1] - w[0] * w[0]
y1 = 1.0 - w[0]
y = 100.0 * x1 * x1 + y1 * y1
return y
# 関数3
def snx3(k, x, dx) :
w = np.empty(2, np.float)
w[0] = x[0] + k * dx[0]
w[1] = x[1] + k * dx[1]
x1 = 1.5 - w[0] * (1.0 - w[1])
y1 = 2.25 - w[0] * (1.0 - w[1] * w[1])
z1 = 2.625 - w[0] * (1.0 - w[1] * w[1] * w[1])
y = x1 * x1 + y1 * y1 + z1 * z1
return y
############################################
# 微係数を計算する
############################################
# 関数1
def dsnx1(x, dx) :
dx[0] = -2.0 * (x[0] - 1.0)
dx[1] = -2.0 * (x[1] - 2.0)
# 関数2
def dsnx2(x, dx) :
dx[0] = 400.0 * x[0] * (x[1] - x[0] * x[0]) + 2.0 * (1.0 - x[0])
dx[1] = -200.0 * (x[1] - x[0] * x[0])
# 関数3
def dsnx3(x, dx) :
dx[0] = 2.0 * (1.0 - x[1]) * (1.5 - x[0] * (1.0 - x[1])) + 2.0 * (1.0 - x[1] * x[1]) * (2.25 - x[0] * (1.0 - x[1] * x[1])) + 2.0 * (1.0 - x[1] * x[1] * x[1]) * (2.625 - x[0] * (1.0 - x[1] * x[1] * x[1]))
dx[1] = -2.0 * x[0] * (1.5 - x[0] * (1.0 - x[1])) - 4.0 * x[0] * x[1] * (2.25 - x[0] * (1.0 - x[1] * x[1])) - 6.0 * x[0] * x[1] * x[1] * (2.625 - x[0] * (1.0 - x[1] * x[1] * x[1]))
# データの入力
sw = 0
line = sys.stdin.readline()
s = line.split()
fun = int(s[1])
n = int(s[3])
max = int(s[5])
opt_1 = int(s[7])
line = sys.stdin.readline()
s = line.split()
eps = float(s[1])
step = float(s[3])
x = np.empty(n, np.float)
dx = np.empty(n, np.float)
y = np.empty(1, np.float)
line = sys.stdin.readline()
s = line.split()
for i1 in range(0, n) :
x[i1] = float(s[i1+1])
# 実行
if fun == 1 :
sw = conjugate(opt_1, max, n, eps, step, y, x, dx, snx1, dsnx1)
elif fun == 2 :
sw = conjugate(opt_1, max, n, eps, step, y, x, dx, snx2, dsnx2)
else :
sw = conjugate(opt_1, max, n, eps, step, y, x, dx, snx3, dsnx3)
# 結果の出力
if sw < 0 :
print(" 収束しませんでした!", end="")
if sw == -1 :
print("(収束回数)")
elif sw == -2 :
print("(1次元最適化の区間)")
else :
print("(黄金分割法)")
else :
print(" 結果=", end="")
for i1 in range(0, n) :
print(str(x[i1]) + " ", end="")
print(" 最小値=" + str(y[0]) + " 回数=" + str(sw))