赞
踩
pip install numpy pandas pygame matplotlib #四个库
pip install lddya==2.0.1 #作者的自用库,里面有一些工具下文会用到
from lddya.Algorithm import ACO #导入ACO算法 from lddya.Draw import ShanGeTu,IterationGraph #导入栅格图、迭代图的绘制模块 from lddya.Map import Map #导入地图文件读取模块 m = Map() m.load_map_file('map.txt') # 读取地图文件 aco = ACO(map_data=m.data,start=[0,0],end=[19,19]) #初始化ACO,不调整任何参数的情况下,仅提供地图数据即可,本行中数据由Map.data提供,start跟end都是[y,x]格式,默认[0,0],[19,19]。 aco.run() # 迭代运行 sfig = ShanGeTu(map_data = m.data) # 初始化栅格图绘制模块 sfig.draw_way(aco.way_data_best) # 绘制路径信息,路径数据由ACO.way_data_best提供。 sfig.save('123.jpg') #保存栅格图数据为'123.jpg' dfig = IterationGraph(data_list= [aco.generation_aver,aco.generation_best], #绘制数据: 每代平均、每代最优路径信息 style_list=['--r','-.g'], # 线型 (规则同plt.plot()中的线型规则) legend_list=['每代平均','每代最优'], # 图例 (可选参数,可以不写) xlabel='迭代次数', # x轴标签,默认“x” ylabel= '路径长度' # y轴标签,默认“y” ) # 初始化迭代图绘制模块 dfig.save('321.jpg') #迭代图保存为321.jpg
下面为某地图文件内容,数字位置与栅格图的黑白栅格一一对应。
这篇《个人库的一些小工具》文章中介绍了地图识别的功能,需要的可以看看。
PS: 注意,Map.data本质上是基于numpy的0-1矩阵。
00000000110100000000 00111000100000100000 00100110001100100110 00000011101100000110 00110011100001110000 00110000000111011110 00000010000111011110 00001011110111011110 00001001000000000000 00001101001111000000 00000101101111000000 01110000101111000000 01110011101111000000 01110011100001010000 11000111111001000010 00000011100001110000 00000011100001111000 01100011101100001110 01101000000100000000 00000000000000000000
下图所示的栅格图即为上文的栅格数据文件对应的图,左上角栅格坐标为[0,0],向下y增大,向右x增大。所以右下角为[19,19]。
下图就是算法的迭代图。
如果你只是想使用ACO解决问题,下面的内容就不用看了,效果不好就调参吧。考虑存在朋友仅想阅读代码,这里我附一下ACO的代码供学习参考。
class Ant(): def __init__(self,start,end,max_step,pher_imp,dis_imp) -> None: self.max_step = max_step # 蚂蚁最大行动力 self.pher_imp = pher_imp # 信息素重要性系数 self.dis_imp = dis_imp # 距离重要性系数 self.start = start # 蚂蚁初始位置[y,x] = [0,0],考虑到列表索引的特殊性,先定y,后定x self.destination = end # 默认的终点节点(在run方法中会重新定义该值) self.successful = True #标志蚂蚁是否成功抵达终点 self.record_way = [start] #路径节点信息记录 def run(self,map_data,pher_data): self.position = copy.deepcopy(self.start) #Step 1:不断找下一节点,直到走到终点或者力竭 for i in range(self.max_step): r = self.select_next_node(map_data,pher_data) if r == False: self.successful = False break else: if self.position == self.destination: break else: self.successful = False def select_next_node(self,map_data,pher_data): ''' Function: --------- 选择下一节点,结果直接存入self.postion,仅返回一个状态码True/False标志选择的成功与否。 ''' y_1 = self.position[0] x_1 = self.position[1] #Step 1:计算理论上的周围节点 node_be_selected = [[y_1-1,x_1-1],[y_1-1,x_1],[y_1-1,x_1+1], #上一层 [y_1,x_1-1], [y_1,x_1+1], #同层 [y_1+1,x_1-1],[y_1+1,x_1],[y_1+1,x_1+1], #下一层 ] #Step 2:排除非法以及障碍物节点 node_be_selected_1 = [] for i in node_be_selected: if i[0]<0 or i[1]<0: continue if i[0]>=len(map_data) or i[1]>=len(map_data): continue if map_data[i[0]][i[1]] == 0: node_be_selected_1.append(i) if len(node_be_selected_1) == 0: # 如果无合法节点,则直接终止节点的选择 return False if self.destination in node_be_selected_1: # 如果到达终点旁,则直接选中终点 self.position = self.destination self.record_way.append(copy.deepcopy(self.position)) map_data[self.position[0]][self.position[1]] = 1 return True #Step 3:计算节点与终点之间的距离,构建距离启发因子 dis_1 = [] # 距离启发因子 for i in node_be_selected_1: dis_1.append(((self.destination[0]-i[0])**2+(self.destination[1]-i[1])**2)**0.5) #Step 3.1:倒数反转 for j in range(len(dis_1)): dis_1[j] = 1/dis_1[j] #Step 4:计算节点被选中的概率 prob = [] for i in range(len(node_be_selected_1)): p = (dis_1[i]**self.dis_imp) * (pher_data[y_1*len(map_data)+x_1][node_be_selected_1[i][0]*len(map_data)+node_be_selected_1[i][1]]**self.pher_imp) prob.append(p) #Step 5:轮盘赌选择某节点 prob_sum = sum(prob) for i in range(len(prob)): prob[i] = prob[i]/prob_sum rand_key = np.random.rand() for k,i in enumerate(prob): if rand_key<=i: break else: rand_key -= i #Step 6:更新当前位置,并记录新的位置,将之前的位置标记为不可通过 self.position = copy.deepcopy(node_be_selected_1[k]) self.record_way.append(copy.deepcopy(self.position)) map_data[self.position[0]][self.position[1]] = 1 return True class ACO(): def __init__(self,map_data,start = [0,0],end = [19,19],max_iter = 100,ant_num = 50,pher_imp = 1,dis_imp = 10,evaporate = 0.7,pher_init = 8) -> None: ''' Params: -------- pher_imp : 信息素重要性系数\n dis_imp : 距离重要性系数\n evaporate: 信息素挥发系数(指保留的部分)\n pher_init: 初始信息素浓度\n ''' #Step 0: 参数定义及赋值 self.max_iter = max_iter #最大迭代次数 self.ant_num = ant_num #蚂蚁数量 self.ant_gener_pher = 1 #每只蚂蚁携带的最大信息素总量 self.pher_init = pher_init #初始信息素浓度 self.ant_params = { #生成蚂蚁时所需的参数 'dis_imp':dis_imp, 'pher_imp': pher_imp, 'start' : start, 'end' : end } self.map_data = map_data.copy() #地图数据 self.map_lenght = self.map_data.shape[0] #地图尺寸,用来标定蚂蚁的最大体力 self.pher_data = pher_init*np.ones(shape=[self.map_lenght*self.map_lenght, self.map_lenght*self.map_lenght]) #信息素矩阵 self.evaporate = evaporate #信息素挥发系数 self.generation_aver = [] #每代的平均路径(大小),绘迭代图用 self.generation_best = [] #每代的最短路径(大小),绘迭代图用 self.way_len_best = 999999 self.way_data_best = [] #最短路径对应的节点信息,画路线用 def run(self): #总迭代开始 for i in range(self.max_iter): self.success_way_list = [] print('第',i,'代: ',end = '') #Step 1:当代若干蚂蚁依次行动 for j in range(self.ant_num): ant = Ant(start =self.ant_params['start'],end=self.ant_params['end'], max_step=self.map_lenght*3,pher_imp=self.ant_params['pher_imp'],dis_imp=self.ant_params['dis_imp']) ant.run(map_data=self.map_data.copy(),pher_data=self.pher_data) if ant.successful == True: #若成功,则记录路径信息 self.success_way_list.append(ant.record_way) print(' 成功寻路个数:',len(self.success_way_list),end= '') #Step 2:计算每条路径对应的长度,后用于信息素的生成量 way_lenght_list = [] for j in self.success_way_list: way_lenght_list.append(self.calc_total_lenght(j)) #Step 3:更新信息素浓度 # step 3.1: 挥发 self.pher_data = self.evaporate*self.pher_data # step 3.2: 叠加新增信息素 for k,j in enumerate(self.success_way_list): j_2 = np.array(j) j_3 = j_2[:,0]*self.map_lenght+j_2[:,1] for t in range(len(j_3)-1): self.pher_data[j_3[t]][j_3[t+1]] += self.ant_gener_pher/way_lenght_list[k] #Step 4: 当代的首尾总总结工作 self.generation_aver.append(np.average(way_lenght_list)) self.generation_best.append(min(way_lenght_list)) if self.way_len_best>min(way_lenght_list): a_1 = way_lenght_list.index(min(way_lenght_list)) self.way_len_best = way_lenght_list[a_1] self.way_data_best = copy.deepcopy(self.success_way_list[a_1]) print('平均长度:',np.average(way_lenght_list),'最短:',np.min(way_lenght_list)) def calc_total_lenght(self,way): lenght = 0 for j1 in range(len(way)-1): a1 = abs(way[j1][0]-way[j1+1][0])+abs(way[j1][1]-way[j1+1][1]) if a1 == 2: lenght += 1.41421 else: lenght += 1 return lenght
最后,祝后来诸君学习顺利!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。