# -*- coding: utf-8 -*-
# author: 'boliang'
# date: 2018/4/15 23:39
import math
import matplotlib.pyplot as plt
import numpy as np
class Solution_qmin(object):
def __init__(self, fun=None, epslion=1e-5, deta=1e-4, a=0, b=0, alpha=0, h0=0.5):
if fun == None:
return
self.reset(fun, epslion, deta, a, b, alpha, h0)
def reset(self, fun, epslion=1e-5, deta=1e-4, a=0, b=0, alpha=0, h0=0.5):
self.__fun = lambda x: eval(fun)
self.__fun_str = fun
self.__epslion = epslion
self.__deta = deta
if a == 0 and b == 0:
self.__a, self.__b = self.__get_section(alpha, h0)
else:
self.__a = a
self.__b = b
# 进退法, 获得极小值点的搜索区间
def __get_section(self, alpha, h):
ak = alpha
k = 0
cal_k = self.__fun(ak)
while True:
akp = ak + h
cal_kp = self.__fun(akp)
if cal_kp < cal_k:
h = 2*h
alpha = ak
ak = akp
cal_k = cal_kp
k += 1
else:
if k == 0:
# 反向搜索
h = -h
alpha = akp
akp = ak
cal_kp = cal_k
k = 1
else:
break
return [min(alpha, akp), max(alpha, akp)]
def __draw_image(self, min_x, min_y):
X = np.arange(self.__a-5, self.__b+5, 0.01)
Y = list(map(lambda x: self.__fun(x), X))
plt.plot(X, Y)
plt.title(self.__fun_str, fontSize=16)
plt.xlabel('X', fontSize=16)
plt.ylabel('Y', fontSize=16)
plt.text(min_x, min_y, 'X', color='red', fontSize=14)
plt.text(min_x+0.382, min_y-0.618, '({:.4f}, {:.4f})'.format(min_x, min_y), fontSize=14)
plt.show()
# 抛物线法搜索极小值点
def run(self):
step = 1
h = (self.__b - self.__a)/2
s0 = self.__a
s1 = s0 + h
s2 = s0 + 2*h
cal_0 = self.__fun(s0)
cal_1 = self.__fun(s1)
cal_2 = self.__fun(s2)
while abs(s2 - s0) >= self.__epslion and abs(h) > self.__deta and step < 20:
#更新步长h, 计算插值点
d = (2*(2*cal_1 - cal_0 - cal_2))
pre_h = h
h = (4*cal_1 - 3*cal_0 - cal_2)*h / d
if abs(h - pre_h) < self.__epslion:
break
s_tmp = s0 + h
cal_tmp = self.__fun(s_tmp)
# 插值点函数计算值比中间点要大
if cal_1 <= cal_tmp:
# 插值点在右半峰上, 更新右边区间端点
if s1 < s_tmp:
s2 = s_tmp
cal_2 = cal_tmp
# 插值点在右半峰,更新左边区间端点
else:
s0 = s_tmp
cal_0 = cal_tmp
# 插值点函数计算值比中间点要小
else:
# 插值点在右半峰,更新右端点
if s1 > s_tmp:
s2 = s1
cal_2 = cal_1
# 插值点在左半峰,更新左端点
else:
s0 = s1
cal_0 = cal_1
# 更新中间点
s1 = s_tmp
cal_1 = cal_tmp
step += 1
result = {
'极小值点为:': s1,
'极小值为:': cal_1,
'迭代次数为:': step,
'|s2-s0|:': abs(s2 - s0),
'|fun(s2)-fun(s0)|:': abs(cal_2 - cal_0)
}
for key, value in result.items():
print(key, value)
self.__draw_image(s1, cal_1)
if __name__ == '__main__':
Solution_qmin('x**2 - math.sin(x)', 1e-5, 1e-4, 0, 1).run()
Comments