模拟退火
算法相关参数
- 初始温度:T0
- 当前温度:t
- 结束温度:Tend
- 迭代次数:Times
- 温度衰减系数:a
- 目标函数差值(当前解和新解之间的函数差值):δ
- 接受新解的概率 :p = e-(δ/t)
算法效果分析
- 迭代次数越多,温度衰减系数约大(即温度衰减得越慢),搜索次数越多,程序运行越慢,相对来 得到的解更可信
- “ 渣 男 ” 套 路 : 前 期 广 撒 网 , 后 期 精 准 打 击 。 \color{red}{“渣男”套路:前期广撒网,后期精准打击。} “渣男”套路:前期广撒网,后期精准打击。模拟退火算法前期要增加接受新解的概率,以便于扩大我们的搜索范围,避免陷入局部最优解;算法后期要减少接受新解的概率,避免丢弃当前最优解
- 目标函数差值越大,接受新解的概率越大;随着迭代次数的增加,温度t逐渐减小,接受新解的概率越小
算法步骤
- 数据初始化:计算距离矩阵(dist[i][j]表示i城市与j城市之间的距离);随机得到初始解(起点为0城市);编写距离计算函数
- 在每个温度下,进行Times次迭代
- 每次迭代时:求得新路径并计算其路径长度(通过二次变换法和数据切片交换来求得新解)
- 若得到的新路径长度小于当前路径长度,则更新当前路径和当前路径长度,若与此同时新路径长度还优于最优路径长度,则同时更新最优路径及其长度
- 模拟退火算法的核心:若得到的新路径长度大于等于当前路径长度,则根据相应函数计算概率,通过随机数和此时的概率相比较,从而决定是否接收新路径(即劣解)
- 直到当前温度小于结束温度时,算法结束
- 调参来优化模型
import random
import matplotlib.pyplot as plt
import numpy as np
import math
import sys
import copy
import time
plt.rcParams['font.sans-serif'] = ['KaiTi']
plt.rcParams['axes.unicode_minus'] = False
T0 = 100
Tend = 1e-20
Times = 50000
a = 0.999
coordinates = np.array([[565.0,575.0],[25.0,185.0],[345.0,750.0],[945.0,685.0],[845.0,655.0],
[880.0,660.0],[25.0,230.0],[525.0,1000.0],[580.0,1175.0],[650.0,1130.0],
[1605.0,620.0],[1220.0,580.0],[1465.0,200.0],[1530.0, 5.0],[845.0,680.0],
[725.0,370.0],[145.0,665.0],[415.0,635.0],[510.0,875.0],[560.0,365.0],
[300.0,465.0],[520.0,585.0],[480.0,415.0],[835.0,625.0],[975.0,580.0],
[1215.0,245.0],[1320.0,315.0],[1250.0,400.0],[660.0,180.0],[410.0,250.0],
[420.0,555.0],[575.0,665.0],[1150.0,1160.0],[700.0,580.0],[685.0,595.0],
[685.0,610.0],[770.0,610.0],[795.0,645.0],[720.0,635.0],[760.0,650.0],
[475.0,960.0],[95.0,260.0],[875.0,920.0],[700.0,500.0],[555.0,815.0],
[830.0,485.0],[1170.0, 65.0],[830.0,610.0],[605.0,625.0],[595.0,360.0],
[1340.0,725.0],[1740.0,245.0]])
num = coordinates.shape[0]
coord_x = coordinates[:,0]
coord_y = coordinates[:,1]
route_origin = list(range(num))
sumDist_origin= 0.0
dist = np.zeros((num,num))
def initDist():
for i in range(num):
x_i = coord_x[i]
y_i = coord_y[i]
for j in range(i, num):
x_j = coord_x[j]
y_j = coord_y[j]
dist[i, j] = dist[j, i] = math.sqrt((x_i - x_j) ** 2 + (y_i - y_j) ** 2)
return dist
dist = initDist()
def shuffle(my_list):
"""
对可行解进行排列组合,除去起点
:param my_list: 可行解
:return:
"""
temp_list = my_list[1:]
np.random.shuffle(temp_list)
shuffle_list = my_list[:1] + temp_list
return shuffle_list
def initRoute():
global num, route_origin
route_origin = shuffle(route_origin)
def getSumDist(route, num, dist):
sumDist = 0.0
for i in range(num - 1):
sumDist += dist[int(route[i])][int(route[i + 1])]
sumDist += dist[int(route[num - 1])][int(route[0])]
return sumDist
def getNewRoute(route, time, num):
route_current = copy.copy(route)
u = 0
v = 0
if time % 2 == 0:
while u == 0 | u == num - 1 | v == 0 | v == num - 1:
u = random.randint(0, num - 1)
v = random.randint(0, num - 1)
temp = route_current[u]
route_current[u] = route_current[v]
route_current[v] = temp
else:
c1 = random.randint(1, num - 2)
c2 = random.randint(1, num - 2)
c3 = random.randint(1, num - 2)
sort_c = sorted([c1, c2, c3])
c1 = sort_c[0]
c2 = sort_c[1]
c3 = sort_c[2]
temp1 = route_current[:c1]
temp2 = route_current[c1:c2]
temp3 = route_current[c2:c3]
temp4 = route_current[c3:]
route_current = temp1 + temp3 + temp2 + temp4
return route_current
def SACore():
print("route_origin:", route_origin)
print("sumDist_origin:", sumDist_origin)
route_current = route_origin
sumDist_current = sumDist_origin
route_new = np.zeros(num)
sumDist_new = 0.0
route_best = np.zeros(num)
sumDist_best = sumDist_origin
t = T0
while True:
if t < Tend:
break
for time in range(Times):
route_new = getNewRoute(route_current, time, num)
sumDist_new = getSumDist(route_new, num, dist)
delt = sumDist_new - sumDist_current
if delt <= 0:
route_current = route_new
sumDist_current = sumDist_new
if sumDist_best > sumDist_new:
route_best = route_new
sumDist_best = sumDist_new
else:
p = math.exp(-delt / t)
randomp = random.uniform(0, 1)
if randomp < p:
route_current = route_new
sumDist_current = sumDist_new
t = t * a
print("最佳路径:", route_best)
print("最佳距离:", sumDist_best)
if __name__ == '__main__':
start = time.time()
initRoute()
sumDist_origin = getSumDist(route_origin, num, dist)
SACore()
end = time.time()
print('Running time: %s Seconds' % (end - start))
"""
最佳路径: [0, 21, 49, 19, 22, 29, 6, 1, 41, 20, 30, 17, 16, 2, 44, 31, 48, 34, 38, 35, 33, 36, 39, 37, 47, 23, 5, 14, 4, 3, 24, 45, 43, 15, 28, 46, 25, 26, 12, 13, 51, 10, 11, 50, 32, 42, 9, 8, 7, 40, 18, 27, 0]
最佳距离: 9636.344979299336
最佳路径: [0, 21, 30, 22, 49, 19, 29, 1, 6, 41, 20, 16, 2, 17, 44, 31, 48, 35, 34, 33, 38, 39, 37, 36, 47, 23, 4, 14, 5, 3, 24, 45, 43, 15, 28, 46, 25, 26, 12, 13, 51, 10, 11, 50, 32, 42, 9, 8, 7, 40, 18, 27, 0]
最佳距离: 9451.034445650703
最佳路径: [0, 21, 30, 22, 49, 19, 29, 1, 6, 41, 20, 16, 2, 17, 31, 48, 35, 34, 33, 38, 39, 36, 37, 47, 23, 4, 14, 5, 3, 24, 45, 43, 15, 28, 46, 25, 26, 12, 13, 51, 10, 11, 50, 32, 42, 9, 8, 7, 40, 44, 18, 27, 0]
最佳距离: 9378.514369030105
最佳路径: [0, 21, 30, 22, 19, 49, 29, 1, 6, 41, 20, 16, 2, 17, 31, 48, 35, 34, 33, 38, 39, 36, 37, 47, 23, 4, 14, 5, 3, 24, 45, 43, 15, 28, 46, 25, 26, 12, 13, 51, 10, 11, 50, 32, 42, 9, 8, 7, 40, 44, 18, 27, 0]
最佳距离: 9371.600543296801
最佳路径: [0, 21, 35, 38, 39, 36, 37, 23, 47, 14, 4, 5, 42, 3, 24, 11, 27, 26, 25, 46, 12, 13, 51, 10, 50, 32, 9, 8, 40, 7, 18, 44, 31, 48, 34, 33, 45, 15, 28, 49, 19, 22, 16, 2, 17, 30, 20, 29, 41, 6, 1, 43, 0]
最佳距离: 8858.531529765904
最佳路径: [0, 21, 35, 38, 39, 36, 37, 47, 23, 4, 14, 5, 3, 24, 11, 27, 26, 25, 46, 12, 13, 51, 10, 50, 42, 32, 9, 8, 7, 40, 18, 44, 31, 48, 34, 33, 45, 15, 28, 49, 19, 22, 29, 16, 2, 17, 30, 20, 41, 6, 1, 43, 0]
最佳距离: 8684.306665303991
最佳路径: [0, 21, 35, 38, 39, 36, 37, 47, 23, 4, 14, 5, 3, 24, 11, 27, 26, 25, 46, 12, 13, 51, 10, 50, 32, 42, 9, 8, 7, 40, 18, 44, 31, 48, 34, 33, 45, 15, 28, 49, 19, 22, 29, 16, 2, 17, 30, 20, 41, 6, 1, 43, 0]
最佳距离: 8461.633757845264
最佳路径: [0, 48, 31, 21, 30, 20, 41, 6, 1, 29, 22, 19, 49, 28, 15, 45, 43, 33, 34, 35, 38, 39, 36, 37, 47, 23, 4, 5, 3, 24, 11, 27, 26, 25, 46, 12, 13, 51, 10, 50, 32, 42, 8, 9, 7, 40, 18, 44, 2, 16, 17, 14, 0]
最佳距离: 8398.198925957735
最佳路径: [0, 21, 17, 30, 2, 16, 20, 41, 6, 1, 29, 22, 19, 49, 28, 15, 45, 43, 33, 34, 38, 39, 37, 4, 5, 3, 24, 11, 27, 26, 25, 46, 12, 13, 51, 10, 50, 32, 42, 8, 9, 7, 40, 18, 44, 31, 48, 35, 36, 47, 23, 14, 0]
最佳距离: 8113.096167712638
最佳路径: [0, 21, 17, 2, 16, 30, 20, 41, 6, 1, 29, 22, 19, 49, 28, 15, 45, 43, 33, 34, 38, 39, 37, 4, 5, 3, 24, 11, 27, 26, 25, 46, 12, 13, 51, 10, 50, 32, 42, 9, 8, 7, 40, 18, 44, 31, 48, 35, 36, 47, 23, 14, 0]
最佳距离: 8072.726662911702
最佳路径: [0, 21, 30, 17, 2, 16, 20, 41, 6, 1, 29, 22, 19, 49, 28, 15, 45, 43, 33, 34, 38, 39, 37, 4, 5, 3, 24, 11, 27, 26, 25, 46, 12, 13, 51, 10, 50, 32, 42, 9, 8, 7, 40, 18, 44, 31, 48, 35, 36, 47, 23, 14, 0]
最佳距离: 7947.836346399286
GA结果:
[0, 21, 29, 22, 20, 30, 17, 16, 2, 18, 40, 7, 8, 44, 31, 48, 36, 37, 33, 43, 45, 15, 28, 19, 49, 34, 35, 38, 39, 4, 5, 23, 47, 14, 3, 24, 42, 32, 50, 11, 10, 27, 26, 12, 51, 13, 25, 46, 41, 1, 6, 21, 0]
10112.612313214102
"""