1 | """ |
2 | TSP_ACO: 蚁群算法解决旅行商问题 |
3 | """ |
4 | import random |
5 | import copy |
6 | import matplotlib.pyplot as plt |
7 |
|
8 |
|
9 | epochs = 300 |
10 | ALPHA = 1 |
11 | BETA = 2 |
12 | RHO = 0.5 |
13 | Q = 100.0 |
14 |
|
15 | city_num = 20 |
16 | ant_num = city_num |
17 | location_x = [ |
18 | 178, 272, 176, 171, 650, 499, 267, 703, 408, 437, |
19 | 428, 614, 36, 360, 482, 666, 597, 209, 201, 492] |
20 | location_y = [ |
21 | 170, 395, 198, 151, 242, 556, 57, 401, 305, 421, |
22 | 490, 213, 524, 244, 114, 104, 552, 70, 425, 227] |
23 |
|
24 |
|
25 | distance_graph = [[0.0 for col in range(city_num)] for raw in range(city_num)] |
26 | pheromone_graph = [[1.0 for col in range(city_num)] for raw in range(city_num)] |
27 |
|
28 | print('TSP By ACO......') |
29 | print('The number of cities: ', str(city_num)) |
30 |
|
31 |
|
32 |
|
33 | class Ant(object): |
34 | |
35 | def __init__(self, ID): |
36 | self.ID = ID |
37 | self.__clean_data() |
38 |
|
39 | |
40 | def __clean_data(self): |
41 | self.path = [] |
42 | self.total_distance = 0.0 |
43 | self.move_count = 0 |
44 | self.current_city = -1 |
45 | self.open_table_city = [True for i in range(city_num)] |
46 | city_index = random.randint(0, city_num - 1) |
47 | self.current_city = city_index |
48 | self.path.append(city_index) |
49 | self.open_table_city[city_index] = False |
50 | self.move_count = 1 |
51 |
|
52 | |
53 | def __choice_next_city(self): |
54 | next_city = -1 |
55 | select_citys_prob = [0.0 for i in range(city_num)] |
56 | total_prob = 0.0 |
57 | |
58 | for i in range(city_num): |
59 | if self.open_table_city[i]: |
60 | |
61 | select_citys_prob[i] = pow(pheromone_graph[self.current_city][i], ALPHA) * pow( |
62 | (1.0 / distance_graph[self.current_city][i]), BETA) |
63 | total_prob += select_citys_prob[i] |
64 |
|
65 | |
66 | if total_prob > 0.0: |
67 | |
68 | temp_prob = random.uniform(0.0, total_prob) |
69 | for i in range(city_num): |
70 | if self.open_table_city[i]: |
71 | |
72 | temp_prob -= select_citys_prob[i] |
73 | if temp_prob < 0.0: |
74 | next_city = i |
75 | break |
76 |
|
77 | if next_city == -1: |
78 | next_city = random.randint(0, city_num - 1) |
79 | while self.open_table_city[next_city] is False: |
80 | next_city = random.randint(0, city_num - 1) |
81 |
|
82 | |
83 | return next_city |
84 |
|
85 | |
86 | def __cal_total_distance(self): |
87 | temp_distance = 0.0 |
88 | for i in range(1, city_num): |
89 | start, end = self.path[i], self.path[i - 1] |
90 | temp_distance += distance_graph[start][end] |
91 | |
92 | end = self.path[0] |
93 | temp_distance += distance_graph[start][end] |
94 | self.total_distance = temp_distance |
95 |
|
96 | |
97 | def __move(self, next_city): |
98 | self.path.append(next_city) |
99 | self.open_table_city[next_city] = False |
100 | self.total_distance += distance_graph[self.current_city][next_city] |
101 | self.current_city = next_city |
102 | self.move_count += 1 |
103 |
|
104 | |
105 | def search_path(self): |
106 | |
107 | self.__clean_data() |
108 |
|
109 | |
110 | while self.move_count < city_num: |
111 | |
112 | next_city = self.__choice_next_city() |
113 | self.__move(next_city) |
114 |
|
115 | |
116 | self.__cal_total_distance() |
117 |
|
118 |
|
119 |
|
120 | class TSP: |
121 | def __init__(self): |
122 | self.ants = [Ant(ID) for ID in range(ant_num)] |
123 | self.best_ant = Ant(-1) |
124 | self.best_ant.total_distance = 1 << 31 |
125 | self.iter = 1 |
126 | |
127 | for i in range(city_num): |
128 | for j in range(city_num): |
129 | pheromone_graph[i][j] = 1.0 |
130 | |
131 | for i in range(city_num): |
132 | for j in range(city_num): |
133 | temp_distance = pow((location_x[i] - location_x[j]), 2) + pow((location_y[i] - location_y[j]), 2) |
134 | temp_distance = pow(temp_distance, 0.5) |
135 | distance_graph[i][j] = float(int(temp_distance + 0.5)) |
136 |
|
137 | |
138 | def __update_pheromone_gragh(self): |
139 | |
140 | temp_pheromone = [[0.0 for col in range(city_num)] for raw in range(city_num)] |
141 | for ant in self.ants: |
142 | for i in range(1, city_num): |
143 | start, end = ant.path[i - 1], ant.path[i] |
144 | |
145 | temp_pheromone[start][end] += Q / ant.total_distance |
146 | temp_pheromone[end][start] = temp_pheromone[start][end] |
147 |
|
148 | |
149 | for i in range(city_num): |
150 | for j in range(city_num): |
151 | pheromone_graph[i][j] = pheromone_graph[i][j] * RHO + temp_pheromone[i][j] |
152 |
|
153 | |
154 | def search_path(self): |
155 | while self.iter < epochs: |
156 | |
157 | for ant in self.ants: |
158 | |
159 | ant.search_path() |
160 | |
161 | if ant.total_distance < self.best_ant.total_distance: |
162 | |
163 | self.best_ant = copy.deepcopy(ant) |
164 | |
165 | self.__update_pheromone_gragh() |
166 | |
167 | self.iter += 1 |
168 | return self.best_ant.path, self.best_ant.total_distance |
169 |
|
170 |
|
171 | if __name__ == '__main__': |
172 | print('Start......', end=' ') |
173 | |
174 | best_solution, best_length = TSP().search_path() |
175 | print('Finish.') |
176 | best_path = best_solution + [best_solution[0]] |
177 |
|
178 | |
179 | print('The best path: ' + str(best_path[0]), end='') |
180 | for i in range(1, len(best_path)): |
181 | print(' ->', str(best_path[i]), end='') |
182 | print() |
183 | |
184 | print('The total distance: ', str(best_length)) |
185 |
|
186 | |
187 | X, Y = [], [] |
188 | for i in best_path: |
189 | X.append(location_x[i]) |
190 | Y.append(location_y[i]) |
191 | fig, ax = plt.subplots() |
192 | ax.plot(X, Y, marker='o') |
193 | for i in range(city_num): |
194 | txt = best_path[i] |
195 | ax.annotate(txt, (X[i], Y[i])) |
196 | plt.show() |