基于python语言,实现经典禁忌搜索算法(TS)对车辆路径规划问题(CVRP)进行求解, 优化代码结构,改进Split函数
这里做了简单的参数敏感性分析,比较不同参数组合下两个版本code的最优值与求解时间的差异。具体为:依次设定禁忌长度为10,20,30,其他参数固定不变:最大迭代次数为300,车辆容量为80。具体实验结果如下表:
可以看出,改进后的code,目标函数优化 3% 至 7% 不等,但牺牲了5倍左右的计算时间。这里计算时间以秒为单位。【在进行实验室计算机在同步执行其他程序,所以实验条件不能保证完全相同,但可反应总体情况】
本期代码在前期代码的基础上做了以下改进:
除了以上关键改动之外,还对代码做了细小调整。
(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.tabu_list=None # 禁忌表
self.TL=30 # 禁忌长度
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
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 createActions(n):
action_list=[]
nswap=n//2
#第一种算子(Swap):前半段与后半段对应位置一对一交换
for i in range(nswap):
action_list.append([1,i,i+nswap])
#第二中算子(DSwap):前半段与后半段对应位置二对二交换
for i in range(0,nswap,2):
action_list.append([2,i,i+nswap])
#第三种算子(Reverse):指定长度的序列反序
for i in range(0,n,4):
action_list.append([3,i,i+3])
return action_list
(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()
如有错误,欢迎交流。
有偿获取