爬山算法:
进一步:
模拟退火算法:
已知:
步骤
import math
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
matplotlib.rcParams['font.family'] = 'STSong'
matplotlib.rcParams['font.size'] = 10
def Energy_F1(x):
"""
能量函数
目标函数值作为E(energy),fitness
求目标函数最小值,因此E越小越好
:param x: 解
:return:
"""
return np.sum(x ** 2)
class SimulatedAnnealing(object):
"""
模拟退火
"""
def __init__(self, inner_iter_num, E_end, x_min, x_max, NP, D, T0, T_end, tr, kr):
"""
初始化
:param inner_iter_num: 每个T温度下的迭代次数,内部迭代次数
:param E_end: 截止能量,截止适应度
:param x_min: 下边界
:param x_max: 上边界
:param NP(number population): 种群大小
:param D(dimension): 解的维度
:param T0: temperature0, 初始温度
:param T_end: 截止温度
:param tr: 温度下降速率
:param kr: 分子扰动率,控制分子移动范围,与T0和绝对0度-273.15度有关
"""
# 截止条件
self.inner_iter_num = inner_iter_num
self.E_end = E_end
# 目标空间
self.x_min = x_min
self.x_max = x_max
# 求解者
self.NP = NP
self.D = D
# 算法参数
self.T0 = T0
self.T_end = T_end
self.tr = tr
self.kr = kr
def cooling(self):
"""
降温过程
:return: E_list,元素{(T,i):E}={(当前温度,当前温度下迭代次数):当前最小能量}
"""
# 记录
idx_min = None
E_dict = {}
# 1. 初始温度,初始化种群,初始化分子(个数,多维能量)
T = self.T0
# x.shape=(NP,D)
x = np.random.uniform(self.x_min, self.x_max, (self.NP, self.D))
# 初始能量,所有列按行取
Es = [Energy_F1(one) for one in x[..., :]]
while T > self.T_end:
# inner_iter_num 内部迭代次数
for num in range(self.inner_iter_num):
# 邻域内随机扰动x,产生新解
# 温度越高,分子运动的范围越大,-273.15是绝对0度,分子不再运动
k = np.random.rand() * self.kr
y_range = k * (273.15 + T);
x_new = x + np.random.uniform(-y_range, y_range, (self.NP, self.D))
# 保证在解空间内
for m in range(self.NP):
for n in range(self.D):
while x_new[m, n] < self.x_min or x_new[m, n] > self.x_max:
x_new[m, n] = x[m, n] + np.random.uniform(-0.055, 0.055) * T
# 分子移动后新的能量
E_news = [Energy_F1(one) for one in x_new[..., :]]
for m in range(self.NP):
if E_news[m] < Es[m]:
x[m, :] = x_new[m, :]
else:
# metropolis principle
p = math.exp(-(E_news[m] - Es[m]) / T)
# r属于[0,1)
r = np.random.rand()
if r < p:
x[m, :] = x_new[m, :]
# 记录新的能量
Es[m] = E_news[m]
# 记录每次迭代的最小能量
E_min = min(Es)
idx_min = Es.index(E_min)
E_dict[(T, num)] = E_min
print("温度T=", T, " 内部迭代次数=", num + 1, " 能量=", E_min)
# 达到截止能量退出
if E_min < self.E_end:
return x[idx_min, :], E_dict
# 温度
T = self.tr * T
pass
return x[idx_min, :], E_dict
def show(self, x_best, E_dict):
"""
展示
:param x_best: 最优解
:param E_dict: 最低能量数组
:return:
"""
print("最优分子:", str(x_best))
print("最优解:", str(list(E_dict.values())[-1]))
plt.title("迭代过程")
plt.xlabel("迭代次数")
plt.ylabel("能量E")
x = range(1, len(E_dict) + 1)
y = list(E_dict.values())
plt.plot(x, y, label="SA")
plt.legend()
plt.show()
if __name__ == '__main__':
sa = SimulatedAnnealing(10, 1e-4, -30, 30, 50, 20, 1000, 10, 0.9, 0.001)
x_best, E_dict = sa.cooling()
sa.show(x_best, E_dict)