我是Optaplanner的新手,我一直在寻求将VRP扩展到不同的问题空间。我正在使用6.1.0-Final。这是一个非常难以解决的问题,但这里有:
规划实体 - 运输(延伸停顿),由运输公司(即货船)锚定 规划变量 - 终端(货物目的地),当然还有隐式转运车(在VRP示例中像车辆一样的阴影变量)
在此路线问题中,货件直接运输到终端,然后返回工厂。即运输商服务于一个终端然后返回工厂。有一系列不同容量/速度的运输车。终端有一个位置,它定义了它与工厂之间的距离。运输商可以服务多个货物,但受到每次运输的往返行程时间和“预定出发窗口”的限制。因此,使用Transporter作为锚点创建链,链接到它所服务的所有货件。
我几乎用时间窗口示例复制了VRP,并考虑了这个问题域。有一些称为previousStandstill和arrivalTime的影子变量(这是到达工厂而不是终端)。我修改了ArrivalTimeUpdatingVariableListener,以便计算从最后一批货物退回到工厂的往返时间。我有严格的约束力,以确保与装运相关的运输车实际上在预定的出发窗口内可用,有足够的容量等。我也试图根据货物,运输车和码头的许多属性最大化利润。
我遇到的问题是,货物的到货时间属性与先前货件的计算到货时间(出发时间+旅行时间)之间似乎不匹配。这只发生在一些货物上,而不是全部。由于在到达时间计算中存在对终端以及传输器的依赖,我还尝试添加另一个称为“previousTerminal”的影子变量,并使用它来尝试确保针对Shipment的previousTerminal等于终端对previousStandstill(使用TerminalUpdatingVariableListener)。
然而,这似乎也不起作用,我发现Shipment实例的'previousTerminal'和previousStandstill(Shipment)的终端之间不匹配。同样,这只发生在某些货件上。就好像在不触发TerminalUpdatingVariableListener上的afterVariableChanged事件的情况下更新了针对先前货件的Terminal属性而更新。
这是一个示例输出。在这里,您可以看到货物在'***************不匹配的货件运输时间*******************'之后有一个“上一个终端”与链中先前货件的终端不匹配。
Shipment 00001, amount 150000.0, terminal Terminal G, transporter North Sea LNG 001, previous shipment null, prev shp term Terminal J, lastShipmentTransitTime 0, thisShipmentTransitTime 5844
Shipment 00002, amount 180000.0, terminal Terminal J, transporter North Sea LNG 004, previous shipment null, prev shp term Terminal J, lastShipmentTransitTime 0, thisShipmentTransitTime 9179
Shipment 00003, amount 250000.0, terminal Terminal B, transporter North Sea LNG 002, previous shipment null, prev shp term Terminal J, lastShipmentTransitTime 0, thisShipmentTransitTime 6656
Shipment 00004, amount 180000.0, terminal Terminal J, transporter North Sea LNG 003, previous shipment null, prev shp term Terminal G, lastShipmentTransitTime 0, thisShipmentTransitTime 10199
Shipment 00005, amount 150000.0, terminal Terminal J, transporter North Sea LNG 006, previous shipment null, prev shp term Terminal J, lastShipmentTransitTime 0, thisShipmentTransitTime 11474
Shipment 00006, amount 150000.0, terminal Terminal J, transporter North Sea LNG 004, previous shipment 00002, prev shp term Terminal J, lastShipmentTransitTime 9179, thisShipmentTransitTime 9179
Shipment 00007, amount 100000.0, terminal Terminal J, transporter North Sea LNG 001, previous shipment 00001, prev shp term Terminal G, lastShipmentTransitTime 5844, thisShipmentTransitTime 12239
Shipment 00008, amount 250000.0, terminal Terminal G, transporter North Sea LNG 002, previous shipment 00003, prev shp term Terminal B, lastShipmentTransitTime 6656, thisShipmentTransitTime 5157
Shipment 00009, amount 200000.0, terminal Terminal C, transporter North Sea LNG 003, previous shipment 00004, prev shp term Terminal J, lastShipmentTransitTime 10199, thisShipmentTransitTime 11001
Shipment 00010, amount 150000.0, terminal Terminal E, transporter North Sea LNG 001, previous shipment 00007, prev shp term Terminal G, lastShipmentTransitTime 5844, thisShipmentTransitTime 15085
***************Mismatching shipment transit times*******************
Shipment 00011, amount 200000.0, terminal Terminal J, transporter North Sea LNG 003, previous shipment 00009, prev shp term Terminal B, lastShipmentTransitTime 6286, thisShipmentTransitTime 10199
***************Mismatching shipment transit times*******************
Shipment 00012, amount 100000.0, terminal Terminal J, transporter North Sea LNG 006, previous shipment 00005, prev shp term Terminal J, lastShipmentTransitTime 11474, thisShipmentTransitTime 11474
Shipment 00013, amount 250000.0, terminal Terminal G, transporter North Sea LNG 002, previous shipment 00008, prev shp term Terminal G, lastShipmentTransitTime 5157, thisShipmentTransitTime 5157
Shipment 00014, amount 200000.0, terminal Terminal E, transporter North Sea LNG 003, previous shipment 00011, prev shp term Terminal J, lastShipmentTransitTime 10199, thisShipmentTransitTime 12571
Shipment 00015, amount 150000.0, terminal Terminal E, transporter North Sea LNG 006, previous shipment 00012, prev shp term Terminal J, lastShipmentTransitTime 11474, thisShipmentTransitTime 14143
Shipment 00016, amount 150000.0, terminal Terminal J, transporter North Sea LNG 001, previous shipment 00010, prev shp term Terminal E, lastShipmentTransitTime 15085, thisShipmentTransitTime 12239
Shipment 00017, amount 200000.0, terminal Terminal J, transporter North Sea LNG 003, previous shipment 00014, prev shp term Terminal J, lastShipmentTransitTime 10199, thisShipmentTransitTime 10199
***************Mismatching shipment transit times*******************
我花了很多时间试图了解这里发生了什么。我已经尝试改变ShadowVariable源中的排序,以及许多其他尝试和错误尝试,但似乎没有解决这个链'腐败'。
也许这是我对这个工具的无知,但是我会欣赏一些指导/指示,因为到目前为止,我所看到的一切都给人留下了非常深刻的印象。
非常感谢任何支持和耐心阅读所有这些!
更新 - 遵循'FULL_ASSERT'模式。现在引发了以下异常(之前没有看到这个)......不确定它意味着什么......
Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Solving failed.
...
Caused by: " java.lang.IllegalStateException: Score corruption: the workingScore (-2957hard/57945soft) is not the uncorruptedScore (-2957hard/57964soft) after completedAction (Shipment 00002, amount 180000.0, terminal Terminal G, transporter North Sea LNG 002, previous shipment null, prev shp term Terminal B, lastShipmentTransitTime 0, thisShipmentTransitTime 5157 => [Terminal-8]):
The corrupted scoreDirector has 5 ConstraintMatch(s) which are in excess (and should not be there):
org.optaplanner.examples.shipscheduling.solver/arrivalAfterLoadingWindow/level0/[Shipment 00003, amount 250000.0, terminal Terminal B, transporter North Sea LNG 002, previous shipment 00002, prev shp term Terminal G, lastShipmentTransitTime 5157, thisShipmentTransitTime 6656]=-4456
org.optaplanner.examples.shipscheduling.solver/arrivalAfterLoadingWindow/level0/[Shipment 00008, amount 250000.0, terminal Terminal B, transporter North Sea LNG 002, previous shipment 00003, prev shp term Terminal B, lastShipmentTransitTime 6656, thisShipmentTransitTime 6656]=-112
org.optaplanner.examples.shipscheduling.solver/maximise profit/level1/[Shipment 00013, amount 250000.0, terminal Terminal B, transporter North Sea LNG 002, previous shipment 00008, prev shp term Terminal B, lastShipmentTransitTime 6656, thisShipmentTransitTime 6656]=4009
org.optaplanner.examples.shipscheduling.solver/maximise profit/level1/[Shipment 00008, amount 250000.0, terminal Terminal B, transporter North Sea LNG 002, previous shipment 00003, prev shp term Terminal B, lastShipmentTransitTime 6656, thisShipmentTransitTime 6656]=10410
org.optaplanner.examples.shipscheduling.solver/terminal not big enough for transporter/level0/[[Terminal-2], [Transporter-2], Shipment 00013, amount 250000.0, terminal Terminal B, transporter North Sea LNG 002, previous shipment 00008, prev shp term Terminal B, lastShipmentTransitTime 6656, thisShipmentTransitTime 6656]=-70000
The corrupted scoreDirector has 3 ConstraintMatch(s) which are missing:
org.optaplanner.examples.shipscheduling.solver/arrivalAfterLoadingWindow/level0/[Shipment 00003, amount 250000.0, terminal Terminal B, transporter North Sea LNG 002, previous shipment 00002, prev shp term Terminal G, lastShipmentTransitTime 5157, thisShipmentTransitTime 6656]=-2957
org.optaplanner.examples.shipscheduling.solver/maximise profit/level1/[Shipment 00008, amount 250000.0, terminal Terminal B, transporter North Sea LNG 002, previous shipment 00003, prev shp term Terminal B, lastShipmentTransitTime 6656, thisShipmentTransitTime 6656]=10398
org.optaplanner.examples.shipscheduling.solver/maximise profit/level1/[Shipment 00013, amount 250000.0, terminal Terminal B, transporter North Sea LNG 002, previous shipment 00008, prev shp term Terminal B, lastShipmentTransitTime 6656, thisShipmentTransitTime 6656]=10316
Check your score constraints....
UPDATE - 将Optaplanner核心更新为6.2.0.CR4,并且启用了'FULL_ASSERT'会有一个不同的异常。如果我禁用到达时间规则检查,那么我不再看到任何例外...但我很难理解为什么会这样。是否有关于我需要了解的“撤消行动”的具体内容?
Caused by: java.lang.IllegalStateException: The moveClass (class org.optaplanner.core.impl.heuristic.move.CompositeMove)'s move ([Shipment 00009, amount 200000.0, assigned terminal null, maxTerminalCapacity null, and transporter null, capacity null, profit 0, periodStart 18000, periodEnd 18200, arrival time18000, departure time = 18000, return time 18000, lastShipmentTransitTime 0, thisShipmentTransitTime 0, previous shipment null => [Transporter-2], Shipment 00009, amount 200000.0, assigned terminal null, maxTerminalCapacity null, and transporter null, capacity null, profit 0, periodStart 18000, periodEnd 18200, arrival time18000, departure time = 18000, return time 18000, lastShipmentTransitTime 0, thisShipmentTransitTime 0, previous shipment null => [Terminal-2]]) probably has a corrupted undoMove ([Shipment 00009, amount 200000.0, assigned terminal null, maxTerminalCapacity null, and transporter null, capacity null, profit 0, periodStart 18000, periodEnd 18200, arrival time18000, departure time = 18000, return time 18000, lastShipmentTransitTime 0, thisShipmentTransitTime 0, previous shipment null => null, Shipment 00009, amount 200000.0, assigned terminal null, maxTerminalCapacity null, and transporter null, capacity null, profit 0, periodStart 18000, periodEnd 18200, arrival time18000, departure time = 18000, return time 18000, lastShipmentTransitTime 0, thisShipmentTransitTime 0, previous shipment null => null]). Or maybe there are corrupted score rules.
Check the Move.createUndoMove(...) method of that Move class and enable EnvironmentMode FULL_ASSERT to fail-faster on corrupted score rules.
Score corruption: the lastCompletedStepScore (-6256hard/0soft) is not the undoScore (-19256hard/0soft).
更新 - 修正
好好经过大量的挖掘后我发现了删除:
&& ObjectUtils.notEqual(shadowShipment.getArrivalTime(), arrivalTime)
来自
while (shadowShipment != null) && ObjectUtils.notEqual(shadowShipment.getArrivalTime(), arrivalTime)) {
ArrivalTimeUpdatingVariableListener中的似乎解决了这个问题,虽然我还不完全确定为什么呢......我想这会让它慢一点。
答案 0 :(得分:0)
感谢指导Geoffrey。
问题与while循环中断有关,一旦发现货物到达时间没有改变。某些情况下,'shadowShipment'的到货时间是相同的,但对于链中的后续货物则不然。
我更新了'ArrivalTimeUpdatingListener',如下所示(这样可以正常工作):
protected void updateArrivalTime(ScoreDirector scoreDirector, Shipment sourceShipment) {
//first get the previous shipment and the departure time. If the the previousStandstill is a transporter
//then the departure time will be null
Standstill previousStandstill = sourceShipment.getPreviousStandstill();
Integer departureTime = (previousStandstill instanceof Shipment)
? ((Shipment) previousStandstill).getDepartureTime() : null;
Shipment shadowShipment = sourceShipment;
//calculate the arrival time of the source shipment based on the departure time of the last
Integer arrivalTime = calculateArrivalTime(shadowShipment, departureTime);
//loop through each shipment in the chain from the source shipment forwards
while (shadowShipment != null) {
//only update the arrival time if it has changed
if(ObjectUtils.notEqual(shadowShipment.getArrivalTime(), arrivalTime)) {
scoreDirector.beforeVariableChanged(shadowShipment, "arrivalTime");
shadowShipment.setArrivalTime(arrivalTime);
scoreDirector.afterVariableChanged(shadowShipment, "arrivalTime");
}
//set the variables for the next loop
departureTime = shadowShipment.getDepartureTime();
shadowShipment = shadowShipment.getNextShipment();
arrivalTime = calculateArrivalTime(shadowShipment, departureTime);
}
}