基于python语言,实现经典自适应大邻域算法(ALNS)对车辆路径规划问题(CVRP)进行求解, 优化代码结构,改进Split函数
往期优质资源
-
CVRP系列
-
遗传算法
蚁群算法
禁忌搜索算法
模拟退火算法
自适应大邻域算法
粒子群算法
量子粒子群算法
差分进化算法
MDVRP系列
-
遗传算法
蚁群算法
禁忌搜索算法
模拟退火算法
自适应大邻域算法
粒子群算法
量子粒子群算法
差分进化算法
VRPTW系列
-
遗传算法
蚁群算法
禁忌搜索算法
模拟退火算法
自适应大邻域算法
粒子群算法
量子粒子群算法
差分进化算法
HVRP系列
-
遗传算法
蚁群算法
禁忌搜索算法
模拟退火算法
自适应大邻域算法
粒子群算法
量子粒子群算法
差分进化算法
MDHFVRPTW系列
-
遗传算法
蚁群算法
禁忌搜索算法
模拟退火算法
自适应大邻域算法
粒子群算法
量子粒子群算法
差分进化算法
1. 适用场景
- 求解CVRP
- 车辆类型单一
- 车辆容量不小于需求节点最大需求
- 单一车辆基地
2. 改进效果对比
这里做了简单的参数敏感性分析,比较不同参数组合下两个版本code的最优值与求解时间的差异。具体为:1)设定权重衰减系数为0.1,0.3,0.5 三个不同等级;2)设定退火速率为0.7,0.75,0.8,0.85,0.9,0.95等不同值;3)设定权重更新步长为2,4,6,8,10等不同值,其他参数固定不变:最大迭代次数为10,车辆容量为80。
2.1 实验结果汇总
改进后的split算子是基于图论的,相对比较耗时,再加上ALNS的贪婪算子需要进行多次计算,因此改进后的算法在时间上的增加额外明显。
2.2 目标函数对比
rho = 0.1:
rho = 0.3:
rho = 0.5:
2.3 求解时间对比
rho = 0.1:
rho = 0.3:
rho = 0.5:
3. 求解结果
(1)收敛曲线
(2)车辆路径
(3)输出文件
4. 部分代码
(1)数据结构
# 数据结构:解
class Sol():
def __init__(self):
self.node_no_seq=None # 解的编码
self.obj=None # 目标函数
self.action_id=None # 算子id
self.route_list=None # 解的解码
self.route_distance = None # 车辆路径的长度集合
# 数据结构:网络节点
class Demand():
def __init__(self):
self.id = 0 # 节点id
self.x_coord = 0 # 节点平面横坐标
self.y_coord = 0 # 节点平面纵坐标
self.demand = 0 # 节点需求
# 数据结构:全局参数
class Model():
def __init__(self):
self.best_sol = None # 全局最优解
self.demand_dict = {} # 需求节点集合
self.demand_id_list = []
self.sol_list = [] # 解的集合
self.depot = None # 车场节点
self.number_of_nodes = 0 # 需求节点数量
self.vehicle_cap = 80 # 车辆最大容量
self.distance_matrix = {}
self.popsize = 100 # 种群规模
self.alpha = 2 # 信息启发式因子
self.beta = 3 # 期望启发式因子
self.Q = 100 # 信息素总量
self.rho = 0.5 # 信息素挥发因子
self.tau = {} # 弧信息素集合
self.vehicle_cap=0 # 车辆最大容量
(2)距离矩阵
def calDistanceMatrix(model):
for i in range(len(model.demand_id_list)):
f_n = model.demand_id_list[i]
for j in range(i + 1, len(model.demand_id_list)):
t_n = model.demand_id_list[j]
dist = math.sqrt((model.demand_dict[f_n].x_coord - model.demand_dict[t_n].x_coord) ** 2
+ (model.demand_dict[f_n].y_coord - model.demand_dict[t_n].y_coord) ** 2)
model.distance_matrix[f_n, t_n] = dist
model.distance_matrix[t_n, f_n] = dist
model.tau[f_n, t_n] = 100
model.tau[t_n, f_n] = 100
dist = math.sqrt((model.demand_dict[f_n].x_coord - model.depot.x_coord) ** 2
+ (model.demand_dict[f_n].y_coord - model.depot.y_coord) ** 2)
model.distance_matrix[f_n, model.depot.id] = dist
model.distance_matrix[model.depot.id, f_n] = dist
(3)路径提取
def extractRoutes(node_no_seq,P,depot_id):
route_list = []
route = []
p = P[node_no_seq[0]]
for node_seq in node_no_seq:
if P[node_seq] == p:
route.append(node_seq)
else:
route.insert(0,depot_id)
route.append(depot_id)
route_list.append(route)
route = [node_seq]
p = P[node_seq]
return route_list
(4)破坏算子
# 随机破坏
def createRandomDestory(model):
d=random.uniform(model.rand_d_min,model.rand_d_max)
return random.sample(model.node_id_list,int(d*(len(model.node_id_list)-1)))
# 最坏值破坏
def createWorseDestory(model,sol):
deta_f=[]
for node_no in sol.node_no_seq:
node_no_seq_=copy.deepcopy(sol.node_no_seq)
node_no_seq_.remove(node_no)
obj,_,_=calObj(node_no_seq_,model)
deta_f.append(sol.obj-obj)
sorted_id = sorted(range(len(deta_f)), key=lambda k: deta_f[k], reverse=True)
d=random.randint(model.worst_d_min,model.worst_d_max)
return [sol.node_no_seq[i] for i in sorted_id[:d]]
(5)收敛曲线
# 绘制目标函数收敛曲线
def plotObj(obj_list):
plt.rcParams['font.sans-serif'] = ['SimHei'] #show chinese
plt.rcParams['axes.unicode_minus'] = False # Show minus sign
plt.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()
(6)车辆路径
# 绘制优化车辆路径
def plotRoutes(model):
for route in model.best_sol.route_list:
x_coord=[]
y_coord=[]
for node_no in route:
x_coord.append(model.demand_dict[node_no].x_coord)
y_coord.append(model.demand_dict[node_no].y_coord)
plt.plot(x_coord,y_coord,marker='s',color='b',linewidth=0.5)
plt.show()
(7)输出结果
# 输出结果
def outPut(model):
work=xlsxwriter.Workbook('result.xlsx')
worksheet=work.add_worksheet()
worksheet.write(0, 0, 'id')
worksheet.write(0, 1, 'route')
worksheet.write(0, 2, 'distance')
worksheet.write(0, 3, 'total_distance')
worksheet.write(1,3,model.best_sol.obj)
for id,route in enumerate(model.best_sol.route_list):
r=[str(i)for i in route]
worksheet.write(id + 1, 0, f'v{str(id + 1)}')
worksheet.write(id + 1, 1, '-'.join(r))
worksheet.write(id + 1, 2, model.best_sol.route_distance[id])
work.close()
5. 完整代码
如有错误,欢迎交流。
私信,有偿
参考
- A simple and effective evolutionary algorithm for the vehicle routing problem