1
+ import numpy as np
2
+ import math
3
+ import time
4
+
5
+ def load_data (data_path ):
6
+ """
7
+ 导入数据,得到城市坐标信息
8
+ :param data_path: 数据文件地址 str
9
+ :return: 所有城市的坐标信息 二维 list
10
+ """
11
+ cities = []
12
+ with open (data_path , 'r' ) as f :
13
+ lines = f .readlines ()
14
+ for line in lines :
15
+ x_str , y_str = line .split ()[1 :]
16
+ x , y = int (x_str ), int (y_str )
17
+ cities .append ((x , y ))
18
+ return cities
19
+
20
+ def get_cities_distance (cities ):
21
+ """
22
+ 计算两两城市的距离
23
+ :param cities: 所有城市的坐标 二维 list
24
+ :return: 城市距离矩阵 numpy数组
25
+ """
26
+ dist_matrix = np .zeros ((127 , 127 ))
27
+ n_cities = len (cities )
28
+ for i in range (n_cities - 1 ):
29
+ for j in range (i + 1 , n_cities ):
30
+ dist = get_two_cities_dist (cities [i ], cities [j ])
31
+ dist_matrix [i , j ] = dist
32
+ dist_matrix [j , i ] = dist
33
+ return dist_matrix
34
+
35
+ def get_two_cities_dist (city1 , city2 ):
36
+ """
37
+ 计算两个城市的距离
38
+ :param city1: 第一个城市 长度为2的list
39
+ :param city2: 第二个城市 长度为2的list
40
+ :return: 两城市的距离 double
41
+ """
42
+ x_1 , y_1 = city1
43
+ x_2 , y_2 = city2
44
+ return math .sqrt (math .pow (x_1 - x_2 , 2 ) + math .pow (y_1 - y_2 , 2 ))
45
+
46
+ def get_route_fitness_value (route , dist_matrix ):
47
+ """
48
+ 计算某一路线的适应度
49
+ :param route: 路线 长度为城市个数的 ndarray
50
+ :param dist_matrix: 距离矩阵 ndarray
51
+ :return: 路线的适应度 double
52
+ """
53
+ dist_sum = 0
54
+ for i in range (len (route )- 1 ):
55
+ dist_sum += dist_matrix [route [i ], route [i + 1 ]]
56
+ dist_sum += dist_matrix [route [- 1 ], route [0 ]]
57
+ return 1 / dist_sum
58
+
59
+ def get_all_routes_fitness_value (routes , dist_matrix ):
60
+ """
61
+ 计算所有路线的适应度
62
+ :param routes: 所有路线 ndarray
63
+ :param dist_matrix: 距离矩阵 ndarray
64
+ :return: 所有路线的适应度 ndarray
65
+ """
66
+ fitness_values = np .zeros (len (routes ))
67
+ for i in range (len (routes )):
68
+ f_value = get_route_fitness_value (routes [i ], dist_matrix )
69
+ fitness_values [i ] = f_value
70
+ return fitness_values
71
+
72
+ def init_route (n_route , n_cities ):
73
+ """
74
+ 随机初始化路线
75
+ :param n_route: 初始化的路线数量 int
76
+ :param n_cities: 城市的数量 int
77
+ :return: 路线矩阵 二维ndarray
78
+ """
79
+ routes = np .zeros ((n_route , n_cities )).astype (int )
80
+ for i in range (n_route ):
81
+ routes [i ] = np .random .choice (range (n_cities ), size = n_cities , replace = False )
82
+ return routes
83
+
84
+ def selection (routes , fitness_values ):
85
+ """
86
+ 选择操作
87
+ :param routes: 所有路线 ndarray
88
+ :param fitness_values: 所有路线的适应度 ndarray
89
+ :return: 选择后的所有路线 ndarray
90
+ """
91
+ selected_routes = np .zeros (routes .shape ).astype (int )
92
+ probability = fitness_values / np .sum (fitness_values )
93
+ n_routes = routes .shape [0 ]
94
+ for i in range (n_routes ):
95
+ choice = np .random .choice (range (n_routes ), p = probability )
96
+ selected_routes [i ] = routes [choice ]
97
+ return selected_routes
98
+
99
+ def crossover (routes , n_cities ):
100
+ """
101
+ 交叉操作
102
+ :param routes: 所有路线 ndarray
103
+ :param n_cities: 城市数量 int
104
+ :return: 交叉后的所有路线 ndarray
105
+ """
106
+ for i in range (0 , len (routes ), 2 ):
107
+ r1_new , r2_new = np .zeros (n_cities ), np .zeros (n_cities )
108
+ seg_point = np .random .randint (0 , n_cities )
109
+ cross_len = n_cities - seg_point
110
+ r1 , r2 = routes [i ], routes [i + 1 ]
111
+ r1_cross , r2_cross = r2 [seg_point :], r1 [seg_point :]
112
+ r1_non_cross = r1 [np .in1d (r1 , r1_cross )== False ]
113
+ r2_non_cross = r2 [np .in1d (r2 , r2_cross )== False ]
114
+ r1_new [:cross_len ], r2_new [:cross_len ] = r1_cross , r2_cross
115
+ r1_new [cross_len :], r2_new [cross_len :] = r1_non_cross , r2_non_cross
116
+ routes [i ], routes [i + 1 ] = r1_new , r2_new
117
+ return routes
118
+
119
+ def mutation (routes , n_cities ):
120
+ """
121
+ 变异操作,变异概率为 0.01
122
+ :param routes: 所有路线 ndarray
123
+ :param n_cities: 城市数量 int
124
+ :return: 变异后的所有路线 ndarray
125
+ """
126
+ prob = 0.01
127
+ p_rand = np .random .rand (len (routes ))
128
+ for i in range (len (routes )):
129
+ if p_rand [i ] < prob :
130
+ mut_position = np .random .choice (range (n_cities ), size = 2 , replace = False )
131
+ l , r = mut_position [0 ], mut_position [1 ]
132
+ routes [i , l ], routes [i , r ] = routes [i , r ], routes [i , l ]
133
+ return routes
134
+
135
+ if __name__ == '__main__' :
136
+ start = time .time ()
137
+
138
+ n_routes = 100 # 路线
139
+ epoch = 100000 # 迭代次数
140
+
141
+ cities = load_data ('./cities.txt' ) # 导入数据
142
+ dist_matrix = get_cities_distance (cities ) # 计算城市距离矩阵
143
+ routes = init_route (n_routes , dist_matrix .shape [0 ]) # 初始化所有路线
144
+ fitness_values = get_all_routes_fitness_value (routes , dist_matrix ) # 计算所有初始路线的适应度
145
+ best_index = fitness_values .argmax ()
146
+ best_route , best_fitness = routes [best_index ], fitness_values [best_index ] # 保存最优路线及其适应度
147
+
148
+ # 开始迭代
149
+ not_improve_time = 0
150
+ for i in range (epoch ):
151
+ routes = selection (routes , fitness_values ) # 选择
152
+ routes = crossover (routes , len (cities )) # 交叉
153
+ routes = mutation (routes , len (cities )) # 变异
154
+ fitness_values = get_all_routes_fitness_value (routes , dist_matrix )
155
+ best_route_index = fitness_values .argmax ()
156
+ if fitness_values [best_route_index ] > best_fitness :
157
+ not_improve_time = 0
158
+ best_route , best_fitness = routes [best_route_index ], fitness_values [best_route_index ] # 保存最优路线及其适应度
159
+ else :
160
+ not_improve_time += 1
161
+ if (i + 1 ) % 200 == 0 :
162
+ print ('epoch: {}, 当前最优路线距离: {}' .format (i + 1 , 1 / get_route_fitness_value (best_route , dist_matrix )))
163
+ if not_improve_time >= 2000 :
164
+ print ('连续2000次迭代都没有改变最优路线,结束迭代' )
165
+ break
166
+
167
+ print ('最优路线为:' )
168
+ print (best_route )
169
+ print ('总距离为: {}' .format (1 / get_route_fitness_value (best_route , dist_matrix )))
170
+
171
+ end = time .time ()
172
+ print ('耗时: {}s' .format (end - start ))
0 commit comments