【进阶一】Python实现MDCVRP常见求解算法——蚁群算法(ACO)
基于python语言,实现蚁群算法(ACO)对多车场车辆路径规划问题(MDCVRP)进行求解。
目录
- 往期优质资源
- 1. 适用场景
- 2. 求解效果
- 3. 代码分析
- 4. 数据格式
- 5. 分步实现
- 6. 完整代码
往期优质资源
- python实现6种智能算法求解CVRP问题
- python实现7种智能算法求解MDVRP问题
- python实现7种智能算法求解MDVRPTW问题
- Python版MDHFVRPTW问题智能求解算法代码【TS算法】
- Python版MDHFVRPTW问题智能求解算法代码【SA算法】
- Python版MDHFVRPTW问题智能求解算法代码【GA算法】
- Python版MDHFVRPTW问题智能求解算法代码【DPSO算法】
- Python版MDHFVRPTW问题智能求解算法代码【DE算法】
- Python版MDHFVRPTW问题智能求解算法代码【ACO算法】
- Python版HVRP问题智能求解算法代码【GA算法】
- Python版HVRP问题智能求解算法代码【DPSO算法】
1. 适用场景
- 求解MDCVRP 问题
- 车辆类型单一
- 车辆容量不小于需求节点最大需求
- 多车辆基地
- 各车场车辆总数满足实际需求
2. 求解效果
(1)收敛曲线
(2)车辆路径
3. 代码分析
车俩路径规划问题按照车场数量可分为单一车场路径规划问题和多车场路径规划问题。针对单一车场条件下仅考虑车辆容量限制的路径规划问题前边帖子中已实现ACO算法求解,本文采用ACO算法对多车场条件下仅考虑车辆容量限制的路径规划问题进行求解。为了保持代码的延续性以及求解思路的一致性,这里对上述ACO算法代码进行如下主要修正实现MDCVRP问题的求解。
- Model数据结构类中采用demand_dict属性存储需求节点集合,depot_dict属性储存车场节点集合,demand_id_list属性储存需求节点id集合,distance_matrix属性储存任意节点间的欧式距离;
- Node数据结构类中去掉node_seq属性,增加depot_capacity属性记录车场的车队限制
- splitRoutes函数中分割车辆路径时分配最近车场作为其车辆提供基地(满足车场车队数量限制)
4. 数据格式
以csv文件储存数据,其中demand.csv文件记录需求节点数据,共包含需求节点id,需求节点横坐标,需求节点纵坐标,需求量;depot.csv文件记录车场节点数据,共包含车场id,车场横坐标,车场纵坐标,车队数量。需要注意的是:需求节点id应为整数,车场节点id任意,但不可与需求节点id重复。 可参考github主页相关文件。
5. 分步实现
(1)数据结构
为便于数据处理,定义Sol()类,Node()类,Model()类,其属性如下表:
- Sol()类,表示一个可行解
属性 | 描述 |
---|---|
node_id_list | 需求节点id有序排列集合,对应TSP的解 |
obj | 优化目标值 |
routes | 车辆路径集合,对应CVRP的解 |
- Node()类,表示一个网络节点
属性 | 描述 |
---|---|
id | 物理节点id,可选 |
x_coord | 物理节点x坐标 |
y_coord | 物理节点y坐标 |
demand | 物理节点需求 |
depot_capacity | 车辆基地车队规模 |
- Model()类,存储算法参数
属性 | 描述 |
---|---|
best_sol | 全局最优解,值类型为Sol() |
demand_dict | 需求节点集合(字典),值类型为Node() |
depot_dict | 车场节点集合(字典),值类型为Node() |
demand_id_list | 需求节点id集合 |
sol_list | 可行解集合,值类型为Sol() |
opt_type | 优化目标类型,0:最小车辆数,1:最小行驶距离 |
vehicle_cap | 车辆容量 |
distance_matrix | 网络弧距离 |
popsize | 蚁群规模 |
alpha | 信息启发式因子 |
beta | 期望启发式因子 |
Q | 信息素总量 |
rho | 信息素挥发系数 |
tau | 网络弧信息素 |
tau0 | 路径初始信息素 |
(2)文件读取
def readCsvFile(demand_file,depot_file,model):with open(demand_file,'r') as f:demand_reader=csv.DictReader(f)for row in demand_reader:node = Node()node.id = int(row['id'])node.x_coord = float(row['x_coord'])node.y_coord = float(row['y_coord'])node.demand = float(row['demand'])model.demand_dict[node.id] = nodemodel.demand_id_list.append(node.id)with open(depot_file,'r') as f:depot_reader=csv.DictReader(f)for row in depot_reader:node = Node()node.id = row['id']node.x_coord=float(row['x_coord'])node.y_coord=float(row['y_coord'])node.depot_capacity=float(row['capacity'])model.depot_dict[node.id] = node
(3)计算距离矩阵、初始化路径信息素
def initDistanceTau(model):for i in range(len(model.demand_id_list)):from_node_id = model.demand_id_list[i]for j in range(i+1,len(model.demand_id_list)):to_node_id=model.demand_id_list[j]dist=math.sqrt( (model.demand_dict[from_node_id].x_coord-model.demand_dict[to_node_id].x_coord)**2+(model.demand_dict[from_node_id].y_coord-model.demand_dict[to_node_id].y_coord)**2)model.distance_matrix[from_node_id,to_node_id]=distmodel.distance_matrix[to_node_id,from_node_id]=distmodel.tau[from_node_id,to_node_id]=model.tau0model.tau[to_node_id,from_node_id]=model.tau0for _,depot in model.depot_dict.items():dist = math.sqrt((model.demand_dict[from_node_id].x_coord - depot.x_coord) ** 2+ (model.demand_dict[from_node_id].y_coord -depot.y_coord)**2)model.distance_matrix[from_node_id, depot.id] = distmodel.distance_matrix[depot.id, from_node_id] = dist
(4)目标值计算
适应度计算依赖" splitRoutes “函数对TSP可行解分割得到车辆行驶路线和所需车辆数,在得到各车辆行驶路线后调用” selectDepot “函数,在满足车场车队规模条件下分配最近车场,” calDistance "函数计算行驶距离。
def selectDepot(route,depot_dict,model):min_in_out_distance=float('inf')index=Nonefor _,depot in depot_dict.items():if depot.depot_capacity>0:in_out_distance=model.distance_matrix[depot.id,route[0]]+model.distance_matrix[route[-1],depot.id]if in_out_distance<min_in_out_distance:index=depot.idmin_in_out_distance=in_out_distanceif index is None:print("there is no vehicle to dispatch")route.insert(0,index)route.append(index)depot_dict[index].depot_capacity=depot_dict[index].depot_capacity-1return route,depot_dictdef splitRoutes(node_id_list,model):num_vehicle = 0vehicle_routes = []route = []remained_cap = model.vehicle_capdepot_dict=copy.deepcopy(model.depot_dict)for node_id in node_id_list:if remained_cap - model.demand_dict[node_id].demand >= 0:route.append(node_id)remained_cap = remained_cap - model.demand_dict[node_id].demandelse:route,depot_dict=selectDepot(route,depot_dict,model)vehicle_routes.append(route)route = [node_id]num_vehicle = num_vehicle + 1remained_cap =model.vehicle_cap - model.demand_dict[node_id].demandroute, depot_dict = selectDepot(route, depot_dict, model)vehicle_routes.append(route)return num_vehicle,vehicle_routesdef calRouteDistance(route,model):distance=0for i in range(len(route)-1):from_node=route[i]to_node=route[i+1]distance +=model.distance_matrix[from_node,to_node]return distancedef calObj(node_id_list,model):num_vehicle, vehicle_routes = splitRoutes(node_id_list, model)if model.opt_type==0:return num_vehicle,vehicle_routeselse:distance = 0for route in vehicle_routes:distance += calRouteDistance(route, model)return distance,vehicle_routes
(5)位置更新
在更新蚂蚁位置时,调用 " searchNextNode "函数,依据网络弧信息素浓度及启发式信息搜索蚂蚁下一个可能访问的节点。
def movePosition(model):sol_list=[]local_sol=Sol()local_sol.obj=float('inf')for k in range(model.popsize):#随机初始化蚂蚁为止nodes_id=[int(random.randint(0,len(model.demand_id_list)-1))]all_nodes_id=copy.deepcopy(model.demand_id_list)all_nodes_id.remove(nodes_id[-1])#确定下一个访问节点while len(all_nodes_id)>0:next_node_no=searchNextNode(model,nodes_id[-1],all_nodes_id)nodes_id.append(next_node_no)all_nodes_id.remove(next_node_no)sol=Sol()sol.node_id_list=nodes_idsol.obj,sol.routes=calObj(nodes_id,model)sol_list.append(sol)if sol.obj<local_sol.obj:local_sol=copy.deepcopy(sol)model.sol_list=copy.deepcopy(sol_list)if local_sol.obj<model.best_sol.obj:model.best_sol=copy.deepcopy(local_sol)def searchNextNode(model,current_node_id,SE_List):prob=np.zeros(len(SE_List))for i,node_id in enumerate(SE_List):eta=1/model.distance_matrix[current_node_id,node_id]tau=model.tau[current_node_id,node_id]prob[i]=((eta**model.alpha)*(tau**model.beta))#采用轮盘法选择下一个访问节点cumsumprob=(prob/sum(prob)).cumsum()cumsumprob -= np.random.rand()next_node_id= SE_List[list(cumsumprob > 0).index(True)]return next_node_id
(6)信息素更新
这里采用蚁周模型对网络弧信息素进行更新,在具体更新时可根据可行解的node_id_list属性(TSP问题的解)对所经过的网络弧信息素进行更新。
def upateTau(model):rho=model.rhofor k in model.tau.keys():model.tau[k]=(1-rho)*model.tau[k]#根据解的node_id_list属性更新路径信息素(TSP问题的解)for sol in model.sol_list:nodes_id=sol.node_id_listfor i in range(len(nodes_id)-1):from_node_id=nodes_id[i]to_node_id=nodes_id[i+1]model.tau[from_node_id,to_node_id]+=model.Q/sol.obj
(7)绘制收敛曲线
def plotObj(obj_list):plt.rcParams['font.sans-serif'] = ['SimHei'] #show chineseplt.rcParams['axes.unicode_minus'] = False # Show minus signplt.plot(np.arange(1,len(obj_list)+1),obj_list)plt.xlabel('Iterations')plt.ylabel('Obj Value')plt.grid()plt.xlim(1,len(obj_list)+1)plt.show()
(8)绘制车辆路线
def outPut(model):work=xlsxwriter.Workbook('result.xlsx')worksheet=work.add_worksheet()worksheet.write(0,0,'opt_type')worksheet.write(1,0,'obj')if model.opt_type==0:worksheet.write(0,1,'number of vehicles')else:worksheet.write(0, 1, 'drive distance of vehicles')worksheet.write(1,1,model.best_sol.obj)for row,route in enumerate(model.best_sol.routes):worksheet.write(row+2,0,'v'+str(row+1))r=[str(i)for i in route]worksheet.write(row+2,1, '-'.join(r))work.close()
(9)输出结果
def plotRoutes(model):for route in model.best_sol.routes:x_coord=[model.depot_dict[route[0]].x_coord]y_coord=[model.depot_dict[route[0]].y_coord]for node_id in route[1:-1]:x_coord.append(model.demand_dict[node_id].x_coord)y_coord.append(model.demand_dict[node_id].y_coord)x_coord.append(model.depot_dict[route[-1]].x_coord)y_coord.append(model.depot_dict[route[-1]].y_coord)plt.grid()if route[0]=='d1':plt.plot(x_coord,y_coord,marker='o',color='black',linewidth=0.5,markersize=5)elif route[0]=='d2':plt.plot(x_coord,y_coord,marker='o',color='orange',linewidth=0.5,markersize=5)else:plt.plot(x_coord,y_coord,marker='o',color='b',linewidth=0.5,markersize=5)plt.xlabel('x_coord')plt.ylabel('y_coord')plt.show()
(10)主函数
def run(demand_file,depot_file,Q,tau0,alpha,beta,rho,epochs,v_cap,opt_type,popsize):""":param demand_file: demand file path:param depot_file: depot file path:param Q:信息素总量:param tau0: 路径信息素初始值:param alpha:信息启发式因子:param beta:期望启发式因子:param rho:信息挥发因子:param epochs:迭代次数:param v_cap:车辆容量:param opt_type:优化类型:0:最小化车辆数,1:最小化行驶距离:param popsize:蚁群规模:return:"""model=Model()model.vehicle_cap=v_capmodel.opt_type=opt_typemodel.alpha=alphamodel.beta=betamodel.Q=Qmodel.tau0=tau0model.rho=rhomodel.popsize=popsizesol=Sol()sol.obj=float('inf')model.best_sol=solhistory_best_obj = []readCsvFile(demand_file,depot_file,model)initDistanceTau(model)for ep in range(epochs):movePosition(model)upateTau(model)history_best_obj.append(model.best_sol.obj)print("%s/%s, best obj: %s" % (ep,epochs, model.best_sol.obj))plotObj(history_best_obj)plotRoutes(model)outPut(model)
6. 完整代码
代码和数据文件可获取:
https://download.csdn.net/download/python_n/37365542
【进阶一】Python实现MDCVRP常见求解算法——蚁群算法(ACO)相关推荐
- 【其他】结构技术优化算法--蚁群算法(ant colony optimization)
目录 1 遗传基因算法 2 模拟退火算法 2.1爬山算法 2.2随机概率优化 3 群体智能算法 3.1蚁群算法 3.2粒子群算法 4总结 1 遗传基因算法 遗传算法(Genetic Algorithm ...
- 【进阶四】Python实现(MD)HVRP常见求解算法——蚁群算法(ACO)
蚁群算法+Split 求解异构车辆路径规划问题 目录 信息传递 1. 适用场景 2. 求解效果 3. 代码分析 4. 数据格式 5. 分步实现 6. 完整代码 参考 信息传递 python实现6种智能 ...
- Python实现VRP常见求解算法——蚁群算法(ACO)
基于python语言,实现经典蚁群算法(ACO)对车辆路径规划问题(CVRP)进行求解. 目录 优质资源 1. 适用场景 2. 求解效果 3. 问题分析 4. 数据格式 5. 分步实现 6. 完整代码 ...
- python闭环最短路径_深度学习经典算法 | 蚁群算法解析
蚁群算法基本思想 蚁群算法的基本原理来源于自然界中蚂蚁觅食的最短路径问题.根据昆虫学家的观察,发现自然界的蚂蚁虽然视觉不发达,但它可以在没有任何提示的情况下找到从食物源到巢穴的最短路径,并且能在环境发 ...
- 深度学习经典算法 | 蚁群算法解析
蚁群算法基本思想 蚁群算法的基本原理来源于自然界中蚂蚁觅食的最短路径问题.根据昆虫学家的观察,发现自然界的蚂蚁虽然视觉不发达,但它可以在没有任何提示的情况下找到从食物源到巢穴的最短路径,并且能在环境发 ...
- 智能算法---蚁群算法介绍
蚁群算法是一种群智能算法,也是启发式算法.基本原理来源于自然界蚂蚁觅食的最短路径原理. (一)蚁群算法的由来 蚁群算法最早是由Marco Dorigo等人在1991年提出,他们在研究新型算法的过程中, ...
- matlab教程蚁群算法,蚁群算法怎样用MATLAB仿真
蚁群算法采用matlab开发的仿真平台:算法实现,路径显示,人机交互控制等 希望对你有帮助! 是可以运行的 % the procedure of ant colony algorithm for ...
- 蚁群优化算法的JAVA实现_优化算法|蚁群算法的理解及实现
蚁群算法 1. 蚁群算法基本原理 蚁群算法(Ant Colony Algorithm, ACA)由Marco Dorigo于1992年提出. 蚁群原理: 蚁群算法的基本原理来源于自然界觅食的最短路径原 ...
- 【进阶一】Python实现MDCVRP常见求解算法——差分进化算法(DE)
基于python语言,实现差分进化算法(DE)对多车场车辆路径规划问题(MDCVRP)进行求解. 目录 往期优质资源 1. 适用场景 2. 求解效果 3. 代码分析 4. 数据格式 5. 分步实现 6 ...
最新文章
- php和架构,结构和架构的区别是什么?
- strstr php文档,php字符串函数学习之strstr()
- Bootstrap系列 -- 28. 下拉菜单状态
- python 编程一日一练-2018-12-01:python每日一练(1)
- winform 基础
- arcgis中python坡度计算_ArcGIS不同坡度植被覆盖率分析步骤
- python函数作用域与闭包_python函数名称空间与作用域、闭包
- android学习笔记---手机拍照功能的实现,及原理
- Camtasia2020注册机顶级屏幕录像视频编辑软件安装教程
- Python3 XML解析
- 基于卫星高度计海面高度异常资料获取潮汐调和常数方法及应用matlab代码
- 国产操作系统Deepin的安装
- LR-Web服务器和应用程序服务器区别(性能指标)
- 破解 --- apk文件解析
- (66)-- 多进程爬取腾讯招聘信息
- Node对象的一些方法
- Delphi控件-复合控件
- APP界面设计指南|APP界面设计师必备信息图
- 【SCNU课堂笔记】计划任务、进程管理、Linux启动流程(未完待续)
- 数据结构(五)图---最小生成树(普里姆算法)