-
Notifications
You must be signed in to change notification settings - Fork 8
/
GA.py
376 lines (288 loc) · 8.07 KB
/
GA.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
#!/usr/bin/env python
# coding: utf-8
# # 采用遗传算法解决10城市TSP问题
# 10城市坐标为:
# - 1: (41, 94);
# - 2: (37, 84);
# - 3: (54, 67);
# - 4: (25, 62);
# - 5: (7, 64);
# - 6: (2, 99);
# - 7: (68, 58);
# - 8: (71, 44);
# - 9: (54, 62);
# - 10: (83, 69)
#
# ## 思考:
#
# - 遗传算法求解问题的性能与哪些因素有关?
# - 遗传算法的缺陷有哪些?
# - 有何改进措施?
#
# In[1]:
import numpy as np
import random
import matplotlib.pyplot as plt
# get_ipython().run_line_magic('matplotlib', 'inline')
# # 1. 获取临接矩阵
# In[2]:
def CacDistance(a,b):
"""
计算两点之间的距离
"""
a = np.array(a)
b = np.array(b)
c = a-b
distance = np.sqrt(np.sum(c*c))
return distance
def CityDistance():
"""
获取临接矩阵
"""
locs = [(41, 94),(37, 84),(54, 67),(25, 62),(7, 64),(2, 99),(68, 58),(71, 44),(54, 62),(83, 69)]
n = len(locs)
dis_mat = np.zeros([10,10])
for i in range(n-1):
for j in range(i+1,n):
dist = CacDistance(locs[i],locs[j])
dis_mat[i,j] = dist
for i in range(n):
dis_mat[:,i] = dis_mat[i,:]
return dis_mat
# # 2. 遗传算法
# ## 2.1交叉
# In[3]:
def Cross(p1,p2):
a = np.array(p1).copy()
b = np.array(p2).copy()
# 0~9之间随机生成两个整数,作为映射的起始点和结束点
begin = random.randint(0,9)
end = random.randint(0,9)
# 使 begin 小于 end
if begin > end:
temp = begin
begin = end
end = temp
#print begin,end
# 建立映射关系
cross_map = {}
is_exist = False
# 初步映射
for i in range(begin,end+1):
if a[i] not in cross_map.keys():
cross_map[a[i]] = []
if b[i] not in cross_map.keys():
cross_map[b[i]] = []
cross_map[a[i]].append(b[i])
cross_map[b[i]].append(a[i])
# 处理传递映射 如1:[6],6:[3,1]-->1:[6,3,1],6:[3,1]
# 计算子串中元素出现的个数,个数为2,则该元素为传递的中间结点,如如1:[6],6:[3,1],‘6’出现的次数为2
appear_times = {}
for i in range(begin,end+1):
if a[i] not in appear_times.keys():
appear_times[a[i]] = 0
if b[i] not in appear_times.keys():
appear_times[b[i]] = 0
appear_times[a[i]] += 1
appear_times[b[i]] += 1
if a[i] == b[i]:
appear_times[a[i]] -= 1
for k,v in appear_times.items():
if v == 2:
values = cross_map[k]
for key in values:
cross_map[key].extend(values)
cross_map[key].append(k)
cross_map[key].remove(key)
cross_map[key] = list(set(cross_map[key]))
# 使用映射关系交叉
# 先映射选中的子串
temp = a[begin:end+1].copy()
a[begin:end+1] = b[begin:end+1]
b[begin:end+1] = temp
# 根据映射规则映射剩下的子串
seg_a = a[begin:end+1]
seg_b = b[begin:end+1]
remain = list(range(begin))
remain.extend(range(end+1,len(a)))
for i in remain:
keys = cross_map.keys()
if a[i] in keys:
for fi in cross_map[a[i]]:
if fi not in seg_a:
a[i] = fi
break
if b[i] in keys:
for fi in cross_map[b[i]]:
if fi not in seg_b:
b[i] = fi
break
return a,b
# ## 2.2 变异
# In[4]:
def Variation(s):
c = range(10)
index1,index2 = random.sample(c,2)
temp = s[index1]
s[index1] = s[index2]
s[index2] = temp
return s
# ## 2.3 计算适应度
# In[5]:
def cost(s):
dis = CityDistance()
n = len(s)
cost = 0
for i in range(n):
cost += dis[s[i],s[(i+1)%n]]
return -cost
# ## 2.4 构建遗传算法
# In[6]:
# 获取列表的第三个元素
def TakeThird(elem):
"""
按适应度从大到小,排序时作为sort的key参数
"""
return elem[2]
def CacAdap(population):
"""
# adap n*4,n为行数,每行包括:个体下标,适应度,选择概率,累积概率
"""
# 计算每一个个体的适应度,选择概率
adap = []
psum = 0
# 计算适应度
i = 0
for p in population:
icost = np.exp(cost(p))
psum += icost
# 添加个体下标
adap.append([i])
# 添加适应度
adap[i].append(icost)
i += 1
# 计算选择概率
for p in adap:
# 添加选择概率和累积概率,这里累积概率暂时等于选择概率,后面会重新计算赋值
p.append(p[1]/psum)
p.append(p[2])
# 根据适应度从大到小排序
adap.sort(key=TakeThird,reverse=True)
#print adap
# 计算累计概率
n = len(adap)
for i in range(1,n):
p = adap[i][3] + adap[i-1][3]
adap[i][3] = p
return adap
def Chose(adap):
"""
轮盘选择操作
"""
chose = []
# 选择次数
epochs = 20 #max(len(adap)/2,20)
#while(len(set(chose)) <2):
#print 'chosing...length %d'%len(set(chose))
n = len(adap)
for a in range(epochs):
p = random.random()
if adap[0][3] >= p:
chose.append(adap[0][0])
else:
for i in range(1,n):
if adap[i][3] >= p and adap[i-1][3] < p:
chose.append(adap[i][0])
break
chose = list((chose))
return chose
def Cross_Variation(chose,population):
"""
交叉变异操作
"""
# 交叉率
p_c = 0.7
# 变异率
p_m = 0.3
# 交叉变异操作
chose_num = len(chose)
sample_times = chose_num//2
for i in range(sample_times):
index1,index2 = random.sample(chose,2)
#print index1,index2
# 参与交叉的父结点
parent1 = population[index1]
parent2 = population[index2]
# 这两个父结点已经交叉,后面就不要参与了,就像这两个人以及结婚,按规矩不能在与其他人结婚了,故从采样样本中移除
chose.remove(index1)
chose.remove(index2)
p = random.random()
if p_c >= p:
child1,child2 = Cross(parent1,parent2)
#print child1,child2
p1 = random.random()
p2 = random.random()
if p_m > p1:
child1 = Variation(child1)
if p_m > p2:
child2 = Variation(child2)
population.append(list(child1))
population.append(list(child2))
return population
# In[7]:
def GA(population):
"""
一次遗传过程
"""
adap = CacAdap(population)
# 选择操作
chose = Chose(adap)
# 交叉变异
population = Cross_Variation(chose,population)
return population
# ## 2.5 循环调用遗传算法,直到达到终止条件
# In[8]:
def find_min(population):
loss = []
# 遗传次数
epochs = 51
i = 0
while i < epochs:
adap = []
# 计算适应度
for p in population:
icost = cost(p)
adap.append(icost)
# 使用遗传算法更新种群
population = GA(population)
min_cost = max(adap)
if i%10 == 0:
print('epoch %d: loss=%.2f'%(i,-min_cost))
loss.append([i,-min_cost])
i += 1
if i == epochs:
# 输出最优解
p_len = len(population)
for index in range(p_len):
if adap[index] == min_cost:
print('最优路径:')
print(population[index])
print('代价大小:')
print(-min_cost)
break
# 打印损失函数变换
loss = np.array(loss)
plt.plot(loss[:,0],loss[:,1])
plt.title('GA')
plt.show()
# In[9]:
# 初始化
s1 = [1,2,3,4,5,6,7,8,9,0]
s2 = [5,4,6,9,2,1,7,8,3,0]
s3 = [0,1,2,3,7,8,9,4,5,6]
s4 = [1,2,3,4,5,7,6,8,9,0]
population = [s1,s2,s3,s4]
# 调用
find_min(population)
# In[ ]:
# In[ ]: