1 # 模拟退火算法求解三十城市TSP问题 2 # 2018-3-21开始求解 3 # yangmingustb@outlook.com 4 5 6 import math 7 import random 8 import datetime 9 10 class SaTSP(object): 11 12 def __init__(self, tf=0.01, alpha=0.9): 13 self.tf = tf # 最低温度 14 self.alpha = alpha # 降温系数 15 16 # 30城市坐标 17 self.coordinates = [[41, 94], [37, 84], [54, 67], [25, 62], [7, 64], 18 [2, 99], [68, 58], [71, 44], [54, 62], [83, 69], 19 [64, 60], [18, 54], [22, 60], [83, 46], [91, 38], 20 [25, 38], [24, 42], [58, 69], [71, 71], [74, 78], 21 [87, 76], [18, 40], [13, 40], [82, 7], [62, 32], 22 [58, 35], [45, 21], [41, 26], [44, 35], [4, 50] 23 ] 24 25 self.iteration = 200 * len(self.coordinates) # 每一个温度过程中迭代次数 26 27 def initial_temperature(self): # 温度初始化,采用t0=-delta(f)/(ln0.9) 28 # number_list = [] 29 # for index, item in enumerate(self.coordinates): 30 # number_list.append([index, item]) 31 # print(number_list) 32 33 # print(path) 34 # print(path[0]) 35 dist_list = [] 36 for i in range(100): # 生成一百条路径 37 38 path = random.sample(self.coordinates, len(self.coordinates)) # 生成一条随机序列 39 dist_list.append(self.all_dist(path)) 40 41 t0 = -(max(dist_list) - min(dist_list)) / math.log(0.9) # 设置初温 42 print('初始温度是:', t0) 43 return t0 44 45 def convergence(self, t_update, iteration_update): # 收敛 46 while t_update >= 0.01: 47 while iteration_update <= self.iteration: 48 self.metropolis_rule() 49 else: 50 self.shuchu() 51 else: 52 self.shuchu() 53 54 def D_value(self, current_path, update_path): # 变换前后目标函数差值 55 # value_list = [] 56 print('计算两个状态的差值...') 57 current_distance = self.all_dist(current_path) 58 # value_list.append(current_path) 59 update_distance = self.all_dist(update_path) 60 # value_list.append(update_path) 61 d_value = update_distance-current_distance 62 return d_value 63 64 def metropolis_rule(self, current_path, update_path,update_t): 65 de = self.D_value(current_path, update_path) 66 if de < 0: 67 68 current_path = update_path 69 else: 70 p = math.exp(-de/update_t) 71 if random.random() <= p: 72 current_path = update_path 73 74 else: 75 path = self.swap(update_path) 76 self.metropolis_rule(current_path, path,update_t) 77 return current_path 78 79 def first_path(self): # 生成第一条初始化的路径 80 length = len(self.coordinates) 81 # 因为对初值不敏感,生成一条随机序列, 第一条路径是随机的 82 path = random.sample(self.coordinates, length) 83 return path 84 85 def swap(self, path): # 随机交换2个城市顺序 86 print('产生新解...') 87 city_1 = random.randint(0, len(self.coordinates) - 1) # 产生第一个交换点 88 while True: 89 city_2 = random.randint(0, len(self.coordinates) - 1) # 产生第二个交换点 90 if city_2 != city_1: 91 break 92 else: 93 continue 94 path[city_1], path[city_2] = path[city_2], path[city_1] 95 print('产生新解结束') 96 return path 97 98 def update_t(self, t): 99 t_update = self.alpha*t 100 return t_update 101 102 def between_dist(self, point1, point2): # 计算两点距离 103 104 dist_x = point1[0] - point2[0] 105 dist_y = point1[1] - point2[1] 106 dist = dist_x ** 2 + dist_y ** 2 107 dist = math.sqrt(dist) 108 return dist 109 110 def all_dist(self, path): # 计算所有点距离,总共30段距离 111 sum_cities = 0 112 n = len(path) 113 for i in range(n - 1): # 先计算前29段距离 114 sum_cities += self.between_dist(path[i], path[i + 1]) 115 sum_cities += self.between_dist(path[n - 1], path[0]) # 计算第30个点和第一个点的距离,形成闭环 116 return sum_cities 117 118 def shuchu(self): 119 pass 120 121 def main(self): # 函数式编程,调用其它函数,进入这个大循环 122 123 start_time = datetime.datetime.now() 124 t = self.initial_temperature() # 调用生成初温函数 125 current_path = self.first_path() 126 while t > self.tf: # 终止条件 127 iteration_number = 0 128 while iteration_number < self.iteration: # metropolis终止条件 129 update_path = self.swap(current_path) 130 de = self.D_value(current_path, update_path) 131 132 if de < 0: # 如果增量为负值,则接受 133 134 current_path = update_path 135 136 else: # 产生新解比较 137 p = math.exp(-de / t) 138 if random.random() <= p: 139 current_path = update_path 140 141 else: # 否则保留当前解解,而不是一直产生新解比较,注意误区 142 current_path = current_path 143 # else: 144 # path = self.swap(update_path) 145 # self.metropolis_rule(current_path, path, update_t) 146 # return current_path 147 iteration_number += 1 148 t = self.alpha*t 149 distance = self.all_dist(current_path) 150 print(distance) 151 end_time = datetime.datetime.now() 152 this_time = end_time - start_time 153 print('程序运行时间:', this_time) 154 return current_path 155 156 157 s1 = SaTSP() 158 s1.main()