问题描述
电动车辆路径规划问题(Electric Vehicle-Routing Problem, EVRP),相较于传统的VRP需要考虑车辆的电量、里程焦虑。因此,电动车辆路径规划问题需要决策车辆是否需要去充电、决策选择哪个充电站。
本篇推文求解的问题,做出如下合理假设:
- 充电量与充电时长为线性函数关系;
- 所有车辆的最大载重、最大电量相同,且车辆单位距离的电量消耗相同
- 存在多个车场以及若干充电站;
- 客户点分为两类:取货点以及送货点;
- 车辆完成服务之后,无需返回指定车场;
蚁群算法原理
(1)状态转移函数
初始状态下,每条路径上的信息素数量是相同的。同时,初始状态下,每只蚂蚁会通过随机寻找路径的方式前行,信息素释放的数量与搜索路径的目标函数值成反比。随后,搜索过程中,每只蚂蚁根据路径上残留的信息素,计算蚂蚁前往每一个节点的概率,并基于概率选择下一个访问的节点。其中,第 t t t次迭代蚂蚁 k k k从节点 i i i前往节点 j j j的概率 P i j k ( t ) P_{ij}^k(t) Pijk(t)的计算表达式如下:
表达式中, τ i j ( t ) \tau_{ij}(t) τij(t)表示第 t t t次迭代从节点 i i i前往节点 j j j残留的信息素数量, η i j ( t ) \eta_{ij}(t) ηij(t)表示节点 i i i前往节点 j j j的距离长度的倒数, J k J_k Jk表示蚂蚁 k k k还没有访问过的节点的集合。同时, a a a表示信息素因子, b b b表示启发函数因子,这两个参数为蚁群优化算法的关键参数。
(2)更新信息素
在初始状态下,每条路径的信息素数量均设置为0。在搜索过程中,部分信息素会随着时间流逝而挥发,信息素挥发快慢通过参数信息素挥发因子 c c c进行控制。信息素的更新计算表达式如下:
表达式中, Δ τ i j k \Delta \tau_{ij}^k Δτijk蚂蚁 k k k遍历过的路径总长度的倒数, τ i j ( t ) \tau_{ij}(t) τij(t)表示第 t t t次迭代从节点 i i i前往节点 j j j残留的信息素数量。
算法结果
测试数据
1 55.00 50.00 0.00 0.00
2 45.00 68.00 0.00 0.00
3 35.00 70.00 0.00 0.00
4 72.00 66.00 0.00 0.00
5 12.00 68.00 0.00 0.00
6 82.00 65.00 -15.00 90.00
7 40.00 69.00 20.00 90.00
8 80.00 96.00 -20.00 90.00
9 55.00 88.00 20.00 90.00
10 38.00 70.00 -15.00 90.00
11 85.00 66.00 10.00 90.00
12 58.00 69.00 -10.00 90.00
13 85.00 55.00 -20.00 90.00
14 52.00 64.00 16.00 90.00
15 90.00 26.00 -9.00 90.00
16 60.00 30.00 21.00 90.00
17 61.00 47.00 15.00 90.00
18 17.00 63.00 -19.00 90.00
19 31.00 62.00 23.00 90.00
20 52.00 33.00 -11.00 90.00
21 51.00 21.00 -5.00 90.00
22 42.00 41.00 -10.00 90.00
23 36.00 16.00 10.0 90.00
24 28.00 55.00 -10.00 90.00
25 25.00 50.00 -10.00 90.00
26 25.00 52.00 40.00 90.00
27 25.00 55.00 10.00 90.00
28 23.00 52.00 -10.00 90.00
29 23.00 55.00 20.00 90.00
30 20.00 50.00 -10.00 90.00
31 20.00 55.00 10.00 90.00
32 10.00 35.00 -20.00 90.00
33 80.00 40.00 30.00 90.00
34 8.00 40.00 40.00 90.00
35 68.00 45.00 0.00 0.00
36 5.00 35.00 0.00 0.00
37 45.00 45.00 0.00 0.00
38 22.00 40.00 0.00 0.00
39 10.00 10.00 0.00 0.00
节点编号 X坐标 Y坐标 需求(需求为正表示取货、需求为负表示送货) 服务时间
编号前几个 需求和服务时间为0 表示车场(车辆出发地点)
编号后几个 需求和服务时间为0 表示充电场站
代码展示
while iter <= iter_max
% construct ant solution
Population = cell(ant_number, 1);
for m = 1: ant_number
copy_customer_list = List.customer_list;
load = 0;
battery = vehicle.battery;
route_list = cell(data.customer_number,1);
route_count = 1;
flag = 1; % 判断是否需要重新随机选择节点 1表示需要随机选择 0表示不需要
while ~isempty(copy_customer_list)
if flag == 1
depot_id = randi([1, data.depot_number]); % 随机选择出发车场
msize = numel(copy_customer_list);
idx = randperm(msize);
preNode = copy_customer_list(idx(1)); % 随机选择起始节点
route_list{route_count} = [route_list{route_count} depot_id preNode];
load = load + Demand(preNode);
battery = battery - dist(depot_id, preNode);
end
if sum(preNode == List.station_list) == 0
copy_customer_list(copy_customer_list == preNode) = [];
end
r = rand;
nextNode = NextPoint(preNode,Tau,Eta,alpha,beta,Demand,vehicle,load,dist,battery,copy_customer_list,List,data,r,r0);
if isempty(nextNode) % 无后续节点,创建新路径
route_count = route_count + 1;
load = 0; % 重置车辆载重和电量
battery = vehicle.battery;
flag = 1;
elseif sum(nextNode == List.station_list) ~= 0 % 后续节点为充电站
flag = 0;
route_list{route_count} = [route_list{route_count} nextNode];
load = load + Demand(nextNode); % 更新车辆载重与电量
battery = vehicle.battery;
preNode = nextNode;
else
flag = 0;
route_list{route_count} = [route_list{route_count} nextNode];
load = load + Demand(nextNode); % 更新车辆载重与电量
battery = vehicle.battery - dist(preNode, nextNode);
preNode = nextNode;
end
end
Population{m} = CleanVehiclesCustomer(route_list);
end
NV = zeros(ant_number,1); % number of vehicle
Obj = zeros(ant_number,1); % objective value
for i = 1:ant_number
[NV(i), Obj(i)] = CostFun(Population{i}, dist, service_time, vehicle, List, a, b);
end
if iter == 1
[min_Cost,min_index] = min(Obj);
Solution_best = Population{min_index};
Cost_best(iter) = min_Cost;
else
[min_Cost,min_index] = min(Obj);
if min_Cost < Cost_best(iter - 1)
Cost_best(iter) = min_Cost;
Solution_best = Population{min_index};
else
Cost_best(iter) = Cost_best(iter - 1);
end
end
%% print
disp(['Iteration: ',num2str(iter), ' Total Objective Value: ',num2str(Cost_best(iter))]);
fprintf('\n')
%% update the pheromene
Tau = UpdateTau(Tau, Solution_best, rho, Q, a, b, data, service_time, dist, vehicle, List);
iter = iter + 1;
end
若有运筹优化建模及算法定制需求,欢迎联系我们私聊沟通