2015-03-02 51 views
0

我是Optaplanner的新手,我一直在考虑将VRP扩展到不同的问题空间。我正在使用6.1.0-Final。这是一个相当困难的问题,但这里有:Optaplanner - 在使用多个计划变量时链接计划实体'腐败'

规划实体 - 由运输者(即货船)锚定的装运(延伸停泊) 规划变量 - 码头(货物目的地),当然含蓄运输车(作为VRP示例中的车辆之类的影子变量)

在此路线问题中,货物直接运输到终端,然后返回到工厂。即运输商服务于一个终端,然后返回到该设施。有一个不同容量/速度的运输车队。终端有一个位置,它定义了它与设施之间的距离。运输公司可以服务多件货物,但受到每次运输的往返行程时间和“预定出发时间窗”的限制。因此,使用Transporter作为锚点创建一个链条,链接到它所服务的所有货件。

我几乎复制了VRP与时间窗口的例子考虑到这个问题的领域。有影子变量称为previousStandstill和arrivalTime(这是到达设施而不是终端)。我修改了ArrivalTimeUpdatingVariableListener,以便计算从最后一批货物返回工厂的往返时间。我有严格的限制,以确保与货运相关的运输公司实际上可在预定的出发时间窗口内提供,具有足够的运力等。我还试图根据货运,运输公司和候机楼的许多属性最大化利润。

我遇到的问题是,货运的到达时间属性与上次装运(出发时间+出行时间)的计算到达时间似乎不匹配。这只会发生在一些货物上,而不是全部。由于在到达时间计算中依赖于终端以及运输者,我还尝试添加另一个名为'previousTerminal'的影子变量,并用它来试图确保针对货件的上一个终端等于终端前一个标准(使用TerminalUpdatingVariableListener)。

但是,这似乎并不奏效,而且我看到Shipment实例上的'PreviousTerminal'与previousStandstill(Shipment)的终端之间不匹配。再次,这只发生在一些货运中。就好像终端属性相对于以前的货件在TerminalUpdatingVariableListener上触发afterVariableChanged事件时得到更新。

下面是一个输出示例。在这里你可以看到货物后面有'***************不匹配货物运输时间*******************'有一个'以前的终端',不符合链中上一批货的终端。

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....

更新 - 更新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).

UPDATE - 修复

好了很多周围挖后,我发现,去除:

&& ObjectUtils.notEqual(shadowShipment.getArrivalTime(), arrivalTime) 

while (shadowShipment != null) && ObjectUtils.notEqual(shadowShipment.getArrivalTime(), arrivalTime)) { 

的ArrivalTimeUpdatingVariableListener内似乎解决问题,虽然我不是完全肯定为什么呢......我猜这会让它放慢一点。

+0

是否开启enviromnentMode FULL_ASSERT使其失败迟早? – 2015-03-02 10:54:09

+0

嗨 - 我现在看到一个异常提出,这是之前没有... ScoreCorruption – Justin 2015-03-02 11:03:48

+0

这意味着它失败的时间越早,越接近腐败第一次创建时。打开TRACE日志记录。看看那个分数腐败例外中描述的举动。当移动发生错误时,查看是否可以调试变量侦听器。 – 2015-03-02 12:46:53

回答

0

感谢指针杰弗里。

该问题与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); } }