Skip to content

Commit 3203e86

Browse files
committed
代码内容已经ok 后续补充文档即可
1 parent 87911ca commit 3203e86

10 files changed

+898
-0
lines changed

.vscode/settings.json

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"python.pythonPath": "C:\\ProgramData\\Anaconda3\\python.exe"
3+
}

algorithms/AntColonyAlgorithm.py

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
'''
2+
Author: Theo_hui
3+
Date: 2020-12-14 20:14:23
4+
Descripttion: 蚁群算法
5+
'''
6+
import random
7+
import math
8+
import time
9+
import numpy as np
10+
11+
from .Heuristic import Heuristic
12+
13+
class AC(Heuristic):
14+
''' 蚁群算法 '''
15+
16+
def __init__(self,
17+
ants_num, # 蚂蚁数量
18+
alpha, # 信息素影响因子
19+
beta, # 期望影响因子
20+
Rho, # 信息素挥发率
21+
Q, # 信息素释放的量 常量
22+
TSP, # TSP实例
23+
iteration=1000 # 迭代次数
24+
):
25+
26+
self.ants_num = ants_num
27+
self.alpha = alpha
28+
self.beta = beta
29+
self.Rho = Rho
30+
self.Q = Q
31+
self.TSP = TSP
32+
self.iteration = iteration # 迭代次数
33+
34+
def cal_path_distance(self,path_mat):
35+
''' 计算距离'''
36+
dis_list=[]
37+
for path in path_mat:
38+
dis_list.append(self.TSP.cal_path_distance(path))
39+
return dis_list
40+
41+
def _remove_same_group_city(self,citys,choose):
42+
''' 移除与choose是同一物品的城市 (包括自己)'''
43+
for group in self.TSP.city_index_groups:
44+
if choose in group:
45+
for city in group:
46+
try:
47+
citys.remove(city)
48+
except Exception as e:
49+
print(city,citys,group)
50+
raise e
51+
return citys
52+
53+
54+
def solve(self, record_step=100):
55+
''' 执行蚁群算法'''
56+
57+
#初始化
58+
items_num = len(self.TSP.city_index_groups) # 物品数量
59+
citys_num = len(self.TSP.city_locations) # 城市数量
60+
distMat=self.TSP.distMat # 距离矩阵
61+
62+
pheromone_mat=np.ones((citys_num,citys_num)) # 信息素浓度矩阵 初始为1
63+
path_mat=np.zeros((self.ants_num,items_num)).astype(int) # 路径矩阵
64+
65+
star_t=time.time()
66+
67+
print("======================[ AC ]===========================")
68+
69+
for count in range(self.iteration):
70+
71+
#1.=== 随机放置蚂蚁 并让所有蚂蚁爬行完毕 ====
72+
for ant in range(self.ants_num):
73+
unvisit_list=list(range(citys_num)) # 未访问的
74+
choose=random.choice(unvisit_list) # 初始随机的放置蚂蚁
75+
unvisit_list=self._remove_same_group_city(unvisit_list,choose) # 移除有同类物品的城市
76+
77+
# 记录开始城市
78+
path_mat[ant,0]=choose
79+
80+
for j in range(1,items_num):
81+
#轮盘法选择下一个城市
82+
trans_list,trans=[],0
83+
for k in range(len(unvisit_list)):
84+
# 计算概率 与信息素浓度成正比, 与距离成反比
85+
trans +=np.power(pheromone_mat[choose][unvisit_list[k]],self.alpha)*np.power(1.0/distMat[choose][k],self.beta)
86+
trans_list.append(trans)
87+
rand=random.uniform(0,trans)#产生随机数
88+
89+
# 转一次轮盘 选择
90+
for t in range(len(trans_list)):
91+
if rand <= trans_list[t]:
92+
choose_next=unvisit_list[t]
93+
break
94+
else:
95+
continue
96+
else:
97+
choose_next=unvisit_list[-1]
98+
path_mat[ant,j]=choose_next#填路径矩阵
99+
100+
# 更新候选城市
101+
visit=choose_next
102+
unvisit_list=self._remove_same_group_city(unvisit_list,visit)
103+
104+
#所有蚂蚁的路径表填满之后,算每只蚂蚁的总距离
105+
dis_all_ant_list=self.cal_path_distance(path_mat)
106+
107+
#3.=========== 更新信息素矩阵 ==============
108+
pheromone_change=np.zeros((citys_num,citys_num))
109+
for i in range(self.ants_num):
110+
# 在路径上的每两个相邻城市间留下信息素,与路径距离反比
111+
for j in range(items_num-1):
112+
pheromone_change[path_mat[i,j]][path_mat[i,j+1]] += self.Q/distMat[path_mat[i,j]][path_mat[i,j+1]]
113+
pheromone_change[path_mat[i,items_num-1]][path_mat[i,0]] += self.Q/distMat[path_mat[i,items_num-1]][path_mat[i,0]]
114+
pheromone_mat=(1-self.Rho)*pheromone_mat+pheromone_change
115+
116+
#记录历史最佳值
117+
if count == 0 or min(dis_all_ant_list) < dis_new:
118+
dis_new=min(dis_all_ant_list)
119+
path_new=path_mat[dis_all_ant_list.index(dis_new)].copy()
120+
self.TSP.set_path(path_new)
121+
122+
# 记录迭代的值
123+
if count % record_step==0:
124+
self.costs.append(dis_new)
125+
126+
print("[{}] path:{} cost:{}".format(count,path_new,dis_new).replace("\n",''))
127+
128+
end_t=time.time()
129+
130+
print("=============[ path:{} cost:{} time:{:.4}s]===============".format(self.TSP.path,self.TSP.distance,end_t-star_t))
131+
132+
return self.TSP
133+

algorithms/GeneticAlgorithm.py

+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
'''
2+
Author: Theo_hui
3+
Date: 2020-12-14 20:14:23
4+
Descripttion: 遗传算法
5+
'''
6+
import random
7+
import math
8+
import time
9+
10+
from .Heuristic import Heuristic
11+
12+
class GA(Heuristic):
13+
''' 遗传算法 '''
14+
15+
def __init__(self,
16+
M, # 种群规模
17+
Pc, # 交叉概率
18+
Pm, # 变异概率
19+
TSP, # TSP实例
20+
iteration=1000 # 迭代次数
21+
):
22+
23+
self.M = M
24+
self.Pc = Pc
25+
self.Pm = Pm
26+
self.TSP = TSP
27+
self.iteration = iteration # 迭代次数
28+
29+
def Generate_initial_pops(self):
30+
''' 生成初始种群 '''
31+
pops=[]
32+
33+
for _ in range(self.M):
34+
path=[]
35+
city_index=self.TSP.city_index_groups.copy()
36+
37+
# 随机生成个体
38+
for __ in range(len(self.TSP.city_index_groups)):
39+
group=random.choice(city_index)
40+
path.append(random.choice(group))
41+
city_index.remove(group)
42+
pops.append(path)
43+
44+
45+
46+
return pops
47+
48+
def cal_adaptation(self,pops):
49+
''' 计算种群的适应度 适应度为 10000/距离'''
50+
51+
adaps=[]
52+
for pop in pops:
53+
dist =self.TSP.cal_path_distance(pop) # 计算距离
54+
adap =10000.0/dist # 适应度
55+
adaps.append(adap)
56+
return adaps
57+
58+
def select_prop_operation(self,adaps,pops):
59+
''' 比例选择运算 轮盘赌算法 '''
60+
61+
# 积累分布函数
62+
adap_sum,y=[],0
63+
for adap in adaps:
64+
y+=adap
65+
adap_sum.append(y)
66+
67+
# 保留M*(1-Pc-Pm)个
68+
new_pops=[]
69+
for _ in range(int(self.M*(1-self.Pc-self.Pm))):
70+
rand=random.uniform(0,adap_sum[-1])#产生随机数 转一次轮盘
71+
for j in range(len(adap_sum)):
72+
if rand<adap_sum[j]:
73+
new_pops.append(pops[j])
74+
break
75+
return new_pops
76+
77+
def cross(self,pops):
78+
''' 单点交叉 '''
79+
new_pops=pops.copy()
80+
81+
# 变异M*Pc个
82+
for _ in range(int(self.M*self.Pc)):
83+
which = random.randint(0,len(new_pops)-1) # 选择一个进行交叉
84+
pop=new_pops[which].copy()
85+
while pop in new_pops:
86+
# 必须产生新的
87+
p,q=random.randint(0,len(self.TSP.city_index_groups)-1),random.randint(0,len(self.TSP.city_index_groups)-1)
88+
pop[p],pop[q]=pop[q],pop[p] # 第一次交叉
89+
# m,n=random.randint(0,len(self.TSP.city_index_groups)-1),random.randint(0,len(self.TSP.city_index_groups)-1)
90+
# pop[m],pop[n]=pop[n],pop[m] # 第二次交叉
91+
new_pops.append(pop)
92+
return new_pops
93+
94+
def variation(self,pops):
95+
''' 变异操作 '''
96+
new_pops=pops.copy()
97+
# 变异M*Pm个
98+
for _ in range(int(self.M*self.Pm)):
99+
which = random.randint(0,len(new_pops)-1) # 选择一个进行变异
100+
pop=new_pops[which].copy()
101+
while pop in new_pops:
102+
# 选择同一个物品的城市进行随机替换
103+
group = random.choice([x for x in self.TSP.city_index_groups if len(x)>1]).copy()
104+
for i in range(len(pop)):
105+
if pop[i] in group:
106+
group.remove(pop[i])
107+
pop[i] = random.choice(group)
108+
new_pops.append(pop)
109+
return new_pops
110+
111+
def get_best_pop(self,pops,adaps):
112+
''' 找到最适应的种群 '''
113+
max_adap=max(adaps)
114+
index=adaps.index(max_adap)
115+
116+
return pops[index]
117+
118+
def solve(self, record_step=100):
119+
''' 执行遗传算法'''
120+
121+
#0.========== 初始化种群 ===============
122+
pops = self.Generate_initial_pops() # 初始种群
123+
adaps = self.cal_adaptation(pops) # 适应度
124+
125+
star_t=time.time()
126+
127+
print("======================[ GA ]===========================")
128+
129+
for i in range(self.iteration):
130+
131+
# 记录信息
132+
if i % record_step==0:
133+
pop=self.get_best_pop(pops,adaps)
134+
self.costs.append(self.TSP.cal_path_distance(pop))
135+
136+
#1.======== 比例选择运算 ==========
137+
new_pops=self.select_prop_operation(adaps,pops)
138+
139+
#2.======== 单点交叉 ==========
140+
new_pops=self.cross(new_pops)
141+
142+
#3.======== 变异操作 ==========
143+
new_pops=self.variation(new_pops)
144+
145+
pops=new_pops
146+
adaps=self.cal_adaptation(pops)
147+
148+
# 记录历史最优解
149+
best_path = self.get_best_pop(pops,adaps)
150+
151+
if self.TSP.distance and self.TSP.cal_path_distance(best_path)<self.TSP.distance: self.TSP.set_path(best_path)
152+
if not self.TSP.distance: self.TSP.set_path(best_path)
153+
154+
155+
print("[{}] path:{} cost:{}".format(i,self.get_best_pop(pops,adaps),10000/max(adaps)))
156+
157+
end_t=time.time()
158+
159+
print("=============[ path:{} cost:{} time:{:.4}s]===============".format(self.TSP.path,self.TSP.distance,end_t-star_t))
160+
161+
return self.TSP
162+

algorithms/Heuristic.py

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
'''
2+
Author: Theo_hui
3+
Date: 2020-12-15 10:30:50
4+
Descripttion: 启发式算法的公共父类
5+
'''
6+
import matplotlib.pyplot as plt
7+
8+
class Heuristic:
9+
10+
# 每次迭代的花费
11+
costs=[]
12+
13+
def plot_iter_cost(self):
14+
''' 画出迭代的收敛曲线 '''
15+
16+
x=list(range(len(self.costs)))
17+
y=self.costs
18+
19+
plt.plot(x,y,color='b')
20+
plt.title(self.__class__.__name__)
21+
plt.xlabel('iters')
22+
plt.ylabel('distance')
23+
plt.show()

0 commit comments

Comments
 (0)