我目前正在致力于解决包含取货和送货的 VRP。在当前模型中,
Vehicle
是我的第一个@PlanningEntity
,包含@PlanningListVariable
的LoadJobs
,可以是PICKUP
或DROPOFF
类型。每个 LoadJob
都引用它正在传递的 Load
,并且 Load
类都引用它的 PICKUP
和 DROPOFF
LoadJob
。
我编写了以下约束,以确保两个
LoadJobs
都放在同一个 Vehicle
上(当然,尝试传递从未被拾起的负载是没有意义的,并且拿起货物而不交付它):
fun pickupAndDropoffOnSameVehicle(constraintFactory: ConstraintFactory): Constraint {
return constraintFactory
.forEach(LoadJob::class.java)
.filter { it.load.pickup.vehicle != it.load.dropoff.vehicle }
.penalizeConfigurable()
.asConstraint(PICKUP_AND_DROPOFF_ON_SAME_VEHICLE)
}
当我在
FULL_ASSERT
模式下运行时,出现以下异常:
Caused by: java.lang.IllegalStateException: Score corruption (100hard): the workingScore (-19init/-100hard/0medium/-11670soft) is not the uncorruptedScore (-19init/-200hard/0medium/-11670soft) after completedAction (LoadJob(id=DROPOFF-loDKrYTAqF5kIfjFM6n4) {null -> Vehicle(idx=0)[0]}):
Score corruption analysis:
The corrupted scoreDirector has no ConstraintMatch(s) which are in excess.
The corrupted scoreDirector has 1 ConstraintMatch(s) which are missing:
com.cargonexx.vehiclerouting.solver.constraint/pickupAndDropoffOnSameVehicle/[LoadJob(id=PICKUP-loDKrYTAqF5kIfjFM6n4)]=-100hard/0medium/0soft
Maybe there is a bug in the score constraints of those ConstraintMatch(s).
Maybe a score constraint doesn't select all the entities it depends on, but finds some through a reference in a selected entity. This corrupts incremental score calculation, because the constraint is not re-evaluated if such a non-selected entity changes.
Shadow variable corruption in the corrupted scoreDirector:
None
at org.optaplanner.core.impl.score.director.AbstractScoreDirector.assertScoreFromScratch(AbstractScoreDirector.java:637)
at org.optaplanner.core.impl.score.director.AbstractScoreDirector.assertWorkingScoreFromScratch(AbstractScoreDirector.java:613)
at org.optaplanner.core.impl.score.director.AbstractScoreDirector.doAndProcessMove(AbstractScoreDirector.java:204)
at org.optaplanner.core.impl.heuristic.thread.MoveThreadRunner.run(MoveThreadRunner.java:131)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:577)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1589)
由于错误消息,我猜测这可能是由两个
LoadJobs
通过 Load
类之间的传递关系引起的。我尝试过仅过滤 PICKUP
,然后再过滤同一辆车并加入 LoadJob::class.java
,然后在两个加载作业上过滤相同的 Load
,然后再过滤同一辆车,一切都无济于事.
此异常的原因是什么?如何解决?
这是因为增量分数计算如何与
交互.filter { it.load.pickup.vehicle != it.load.dropoff.vehicle }
没有选择
pickup
或dropoff
,因此ConstraintStreams实现(无论是OptaPlanner CS Drools impl,还是Timefold的faster impl),不知道当上车或下车的车辆变量发生变化时,需要将这个约束重新评估(以增量方式实现可扩展性)。
解决方案
类似:
forEach(pickup)
.join(dropoff, equals(getLoad))
.filter(not same vehicle)
.penalize()