要求
我有一个车队。每辆车都有一个容量和它的存款,这个存款有一个时间窗口。从VRP的OptaPlanner的例子来看,我只对我作为浮点处理的容量做了一个变化。据我所知,OptaPlanner示例中的所有车辆都被移动到一个仓库。在我的情况下,每辆车都有自己的车辆段,每辆车都有自己固定的车辆段,有可能几辆车都有同一个车辆段。
R2-我有访问(送货服务)。每次访问都有一个需求和一个时间窗口。从VRP的OptaPlanner的例子来看,我只做了一个修改,要求我把它作为一个类型“float”来处理。
在OptaPlanner域中,我将vehicle中的变量“capacity”和visit中的变量“demand”修改为“float”类型。
Constraint vehicleCapacity(ConstraintFactory constraintFactory) {
return constraintFactory.from(PlanningVisit.class)
.groupBy(PlanningVisit::getVehicle, sumBigDecimal(PlanningVisit::getDemand))
.filter((vehicle, demand) -> demand.compareTo(vehicle.getCapacity()) > 0)
.penalizeLong(
"vehicle capacity",
HardSoftLongScore.ONE_HARD,
(vehicle, demand) -> demand.subtract(vehicle.getCapacity()).longValue());
}
2-在OptaPlanner的例子中,我理解TW是一个乘以一千的长,但我不知道这个长是否表示一个小时或日期,或者它只是一个小时转换成分钟乘以一千。我所做的是将TW转换为分钟并乘以千,例如,如果它是8am,就绪时间是一个等于'480000'的日志。在服务持续时间的情况下,我不乘以1000,我总是把它视为10分钟。我的转换正确吗?,这是OptaPlanner期望的长吗?
3-我明白,使用OptaPlanner的例子来处理时间窗口,我可以解决这个需求(R2),而不用做任何改动,但是由于我找不到的原因,这并没有给我一个可行的解决方案。例如,它返回给我:花费的时间(5000),最佳得分(-3313987hard/-4156887soft)。
我一定是做错了什么,但我找不到哪里,不仅不符合存款的TW,而且每次访问的到达时间都超过了定义的TW。我不明白为什么我会得到这么大的到达时间,甚至超过定义的限制1天(所有到达时间超过1440000=1400min=24=12am),也就是说,他们在这个时间之后到达。
这是我得到的结果:分数(-3313987硬/-4156887软)
路线1指车辆1所跟随的路线
Depot 1 with TW (8:00 a 13:00)
ready_time: 480000
due_time: 780000
Visit 2 (8:30 a 12:30)
ready_time: 510000
due_time: 750000
service_duraration 10 = 10
arrival_time: 1823943
departure_time: 1833943
Visit 4 (9:30 a 12:30)
ready_time: 570000
due_time: 750000
service_duraration 10
arrival_time: 1739284
departure_time: 1739294
Visit 3 (14:40 a 15:30)
ready_time: 880000
due_time: 930000
service_duraration 10
arrival_time: 1150398
departure_time: 1150408
Depot 2 with TW (12:00 a 17:00)
ready_time: 720000
due_time: 1020000
Visit 1 (14:00 a 16:30)
ready_time: 840000
due_time: 990000
service_duraration 10 = 10
arrival_time: 2523243
departure_time: 2523253
public class ArrivalTimeUpdatingVariableListener implements VariableListener<PlanningVisit> {
...
protected void updateArrivalTime(ScoreDirector scoreDirector, TimeWindowedVisit sourceCustomer) {
Standstill previousStandstill = sourceCustomer.getPreviousStandstill();
Long departureTime = previousStandstill == null ? null
: (previousStandstill instanceof TimeWindowedVisit)
? ((TimeWindowedVisit) previousStandstill).getDepartureTime()
: ((TimeWindowedDepot) ((PlanningVehicle)
previousStandstill).getDepot()).getReadyTime();
TimeWindowedVisit shadowCustomer = sourceCustomer;
Long arrivalTime = calculateArrivalTime(shadowCustomer, departureTime);
while (shadowCustomer != null && !Objects.equals(shadowCustomer.getArrivalTime(),
arrivalTime)) {
scoreDirector.beforeVariableChanged(shadowCustomer, "arrivalTime");
shadowCustomer.setArrivalTime(arrivalTime);
scoreDirector.afterVariableChanged(shadowCustomer, "arrivalTime");
departureTime = shadowCustomer.getDepartureTime();
shadowCustomer = shadowCustomer.getNextVisit();
arrivalTime = calculateArrivalTime(shadowCustomer, departureTime);
}
}
private Long calculateArrivalTime(TimeWindowedVisit customer, Long previousDepartureTime) {
if (customer == null || customer.getPreviousStandstill() == null) {
return null;
}
if (customer.getPreviousStandstill() instanceof PlanningVehicle) {
// PreviousStandstill is the Vehicle, so we leave from the Depot at the best suitable time
return Math.max(customer.getReadyTime(),
previousDepartureTime + customer.distanceFromPreviousStandstill());
}
return previousDepartureTime + customer.distanceFromPreviousStandstill();
}
}
public TimeWindowedVehicleRoutingSolution find(UUID jobId) {
//load VRP from DB
RoutingProblem byJobId = routingProblemRepository.findVRP(jobId);
Set<Vehicle> vehicles = byJobId.getVehicles();
Set<Visit> visits = byJobId.getVisits();
//building solution
List<PlanningDepot> planningDepots = new ArrayList<>();
List<PlanningVehicle> planningVehicles = new ArrayList<>();
List<PlanningVisit> planningVisits = new ArrayList<>();
vehicles.forEach(vehicle -> {
//submit to planner location of the deposit, add to matrix for calculating distance
PlanningLocation planningLocation =
optimizer.submitToPlanner(vehicle.getDepot().getLocation());
//Depot, Vehicle and Visit are my persistence JPA entities, they are not the OptaPlanner
domain entities.
//The OptaPlanner domain entities are: PlanningVehicle, PlanningDepot and PlanningVisit
//I build the entities of the optaplanner domain from my persistence entities
Depot depot = vehicle.getDepot();
TimeWindowedDepot timeWindowedDepot = new TimeWindowedDepot();
TimeWindowedDepot timeWindowedDepot = new TimeWindowedDepot(depot.getId(),
planningLocation, depot.getStart(), depot.getEnd());
PlanningVehicle planningVehicle = new PlanningVehicle();
planningVehicle.setId(vehicle.getId());
planningVehicle.setCapacity(vehicle.getCapacity());
// each vehicle has its deposit
planningVehicle.setDepot(timeWindowedDepot);
planningVehicles.add(planningVehicle);
});
visits.forEach(visit -> {
//submit to planner location of the visit, add to matrix for calculating distance
PlanningLocation planningLocation = optimizer.submitToPlanner(visit.getLocation());
TimeWindowedVisit timeWindowedVisit = new TimeWindowedVisit();
TimeWindowedVisit timeWindowedVisit = new TimeWindowedVisit(visit.getId(),
planningLocation, visit.getLoad(),visit.getStart(), visit.getEnd(),
visit.getServiceDuration());
planningVisits.add(timeWindowedVisit);
});
//create TWVRP
TimeWindowedVehicleRoutingSolution solution = new TimeWindowedVehicleRoutingSolution();
solution.setId(jobId);
solution.setDepotList(planningDepots);
solution.setVisitList(planningVisits);
solution.setVehicleList(planningVehicles);
return solution;
}
public void solve(UUID jobId) {
if (!planRepository.isResolved(jobId)) {
logger.info("Starting solver");
TimeWindowedVehicleRoutingSolution solution = null;
TimeWindowedVehicleRoutingSolution timeWindowedVehicleRoutingSolution = find(jobId);
try {
SolverJob<TimeWindowedVehicleRoutingSolution, UUID> solverJob =
solverManager.solve(jobId, timeWindowedVehicleRoutingSolution);
solution = solverJob.getFinalBestSolution();
save(jobId, solution);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
} else
logger.info("This job already has a solution");
}
对不起,书法的事,英语不是我的语言。
非常感谢杰弗里,我应用了你的建议,找到了我问题的根源。感谢您的帮助!
我将对所发生的事情进行评论,以防对某人有用:碰巧我在计算距离时使用了OptaWeb的示例,该示例使用GrahHopper来实现这一目的,默认情况下它返回最小距离,这是计算与时间一样远的原因。通过引入时间窗口,我打破了比分:
Math.max(customer.getReadyTime(),
previousDepartureTime + customer.distanceFromPreviousStandstill())
我的分数被打破了,因为我没有对所有变量使用相同的转换,即TW:就绪时间和出发时间以分钟为单位并乘以千,而距离以毫秒为单位。
当距离回到我身边时:
因此我的分数被打破了。
我所做的是将我所有的时间变量转换为毫秒:
我有一个使用Google的工具或python库实现的工作车辆路径问题解决方案。我有一个包含9个位置的时间矩阵,每个位置都有时间窗口。所有值均以秒为单位。 (例如,第一个时间窗口是从28800到28800。28800秒相当于上午8:00。我希望在上午8:00访问此位置,即车辆段) 我有意只用一辆车来解决这个问题(本质上是解决一个旅行推销员问题)。我相信我正确地增加了我的维度,但我肯定可能犯了一个错误
目前是否有一种方法可以将流量模式合并到OptaPlanner中并解决包装和交付VRP问题? 比如说,我需要在30辆车中优化500辆今天和明天的提货和交付,其中每辆提货都有1-4小时的时间窗口。如果可能的话,我想在高峰时间避开城市的繁忙地区。 还可以添加(或同时取消)新的皮卡。 我相信这是一个常见的问题。OptaPlanner中是否有合适的解决方案? 谢啦!
我们有一个具有时间和容量约束的VRP示例。 我们的场景如下: 我们有5辆车 我们的问题是,算法有时在得到新请求时,会丢弃一些我们已经标记为可行并添加到车辆调度中的节点(乘客请求)。如何防止丢弃已经添加到解决方案(然后在初始解决方案中)的节点? 我们尝试从初始解决方案中为节点设置int.max惩罚,并对我们当前添加的节点设置稍微小的惩罚。当已经确认的节点稍后被删除时,它确实减少了事件的数量,但它仍然
我是optaplanner的新手,希望能用它来解决VRPTW的取货和送货问题(VRPTWPD)。 我从repo示例中的VRPTW代码开始。我正在努力增加它来解决我的问题。然而,我无法返回一个遵守优先/车辆约束的解决方案(必须在交付之前完成取货,并且两者必须由同一车辆完成)。 我总是返回一个解决方案,其中硬得分是我对这种解决方案的期望(即,我可以将一个小样本问题中的所有违规行为相加,并看到硬得分与我
我有VRP问题。我有车辆起始位置和距离矩阵。我希望在访问某些位置时终止/完成解决方案。 所以我不希望它实际访问位置矩阵的每个索引,但如果访问“必须访问”旁边的不同索引有助于更好的解决方案,那么我没有问题。因为你知道有时候直接从1到3比1-2-3慢。(访问2,这不是必须的,但要走捷径) 我定义了一个成本为0的虚拟仓库,我用它作为结束,因为如果你使用开始,你必须定义结束。我把末端放在基本上是末端位置。
我想使用OptaPlanner(或类似的开源Java框架)来优化自行车信使服务的路线。让我们假设5个信使必须从某个来源地拿起30个信封,并将它们送到某个目的地: 我的五个信使分布在整个城市(所以我没有一个仓库),他们不必回到他们开始的地方: 我将使用以下硬约束: null null