当前位置: 首页 > 知识库问答 >
问题:

Optaplanner-使用多个规划变量时链接的规划实体“损坏”

柳高卓
2023-03-14

我是Optaplanner的新手,我一直在考虑将VRP扩展到一个不同的问题空间。我用的是6.1.0-final。这是一个很难计算的问题,但下面是:

规划实体-装运(扩展Standstill),由运输商(即货船)锚定规划变量-终端(货物目的地),当然隐含运输商(作为VRP示例中的Vehicle这样的影子变量)

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

考虑到这个问题域,我几乎复制了带有时间窗口的VRP示例。有一个影子变量叫做previousStandstill和arrivalTime(这是到达设施,而不是终端)。我已经修改了ArrivalTimeUpdatingVariableListener,以便它计算从最后一批货启程返回设施的往返时间。我有严格的限制,以确保与货物相关的运输公司在预定的离港窗口内确实可用,有足够的运力等。我还试图根据货物、运输公司和码头的一些属性来最大化利润。

我遇到的问题是,货件的arrivalTime属性与前一批货件的计算到达时间(出发时间+旅行时间)之间似乎不匹配。这种情况只发生在部分发货中,而不是全部。由于在到达时间计算中存在对终端和运输者的依赖关系,我还尝试添加另一个名为“previousTerminal”的影子变量,并使用该变量尝试确保针对装运的previousTerminal等于针对previousStandstill的terminal(使用TerminalUpdatingVariableListener)。

但是,这似乎也不起作用,而且我看到了装运实例上的“previousStandstill”(装运)的终端之间的不匹配。同样,这种情况只发生在某些发货中。这就好像更新了针对前一批货的Terminal属性,而没有触发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'模式。下面的异常现在被引发(以前没有看到)...但是不确定它的意思...

线程“awt-eventqueue-0”java.lang.IllegalStateException中出现异常:解决失败。...原因:“java.lang.IllegalStateException:分数损坏:workingScore(-2957Hard/57945Soft)不是completedAction(装运00002,金额180000.0,端子G,北海LNG 002运输车,上一批货为空,前shp项目终端B,lastShipmentTransitTime 0,thisShipmentTransitTime 5157=>[Terminal-8]):损坏的scoreDirector有5个超过(且不应存在)的约束匹配:org.optaplanner.examples.ShipScheduling.Solver/ArrivalAfterLoadingWindow/Level0/[Shipment00003,amount 250000.0,terminal terminal B,transporter North Sea LNG 002,previous ShipmentTransitTime 00002,prev shp terminal G,lastShipmentTransitTime 5157,6656]=4009 org.optaplanner.examples.shipscheduling.solver/最大化利润/Level1/[装运00008,数量250000.0,终端B,运输商北海LNG 002,上一次装运00003,上一次shp条款TerminalB,上一次ShipmentTransitTime 6656,本次ShipmentTransitTime 6656]=10410 org.optaplanner.shipscheduling.solver/终端不够大/Level0/[[终端-2],[运输商-2],装运00013,数量250000.0,终端B,运输商北海LNG 002,上一次装运00008,上一次shp条款TerminalB,上一Eduling.Solver/Maximise Profit/Level1/[装运00008,金额250000.0,终端B,运输商北海LNG 002,上次装运00003,上次shp terminal B,lastShipmentTransitTime 6656,thisShipmentTransitTime 6656]=10398 org.optaplanner.examples.ShipScheduling.Solver/Maximise Profit/Level1/[装运00013,金额2500000,终端B,运输商北海LNG 002,上次装运00008,上次shp terminal B,lastShipmentTransitTime 6656,

UPDATE-将Optaplanner核心更新到6.2.0.cr4,启用“FULL_ASSERT”时出现不同的异常。如果我禁用了到达时间规则检查,那么我就不再看到任何例外了...但是我很难看到这是为什么。关于“撤消移动”有什么我需要知道的具体内容吗?

原因:java.lang.IllegalStateException:moveClass(类org.optaplanner.core.impl.heuristic.move.CompositeMove)的移动([Shipping 00009,金额200000.0,分配的终端为空,maxTerminalCapacity为空,和传输器为空,容量为空,利润0,从18000年开始,18200年底,到达时间18000,出发时间=18000,返回时间18000,lastShipmentTransitTime 0,thisShipmentTransitTime 0,前一批货为空=>[Transporter-2],装运00009,金额200000.0,分配的终端为空,maxTerminalCapacity为空,和传输器为空,容量为空,利润0,从18000年开始,18200年底,到达时间18000,出发时间=18000,返回时间18000,lastShipmentTransitTime 0,thisShipmentTransitTime 0,previous null=>[Terminal-2]])可能有损坏的undoMove([shipment 00009,amount 200000.0,assigned terminal null,maxTerminalCapacity null,transporter null,capacity null,Profile 0,periodStart 18000,periodEnd 18200,arrival time 18000,出发时间=18000,return time 18000,lastShipmentTransitTime 0,或者是评分规则被破坏了。检查Move.CreateUndoMove(...)方法,并启用EnvironmentMode FULL_ASSERT在损坏评分规则上更快地失败。分数损坏:lastCompletedStepScore(-6256Hard/0Soft)不是undoScore(-19256Hard/0Soft)。

更新-修复

好吧,经过大量的挖掘,我已经发现移除:

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

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

在ArrivalTimeUpdatingVariableListener中似乎可以解决这个问题,尽管我还不完全确定为什么...我想这会使问题变慢。

共有1个答案

虞高雅
2023-03-14

谢谢你的指点杰弗里。

这个问题与while循环中断有关,因为它发现一个货件的到达时间没有改变。在某些情况下,shadowshipport的到达时间是相同的,但链中的后续发货则不同。

我已经更新了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);
    }
}
 类似资料:
  • 我正在研究来自OptaPlanner的示例用例。我也找不到任何类似的例子,可以在一个规划实体中求解多个规划变量。例如,在护士名册中,一个轮班的每个可能需要多个分配的。在这种情况下,如何利用planner和编写规则呢?

  • 我用增量java解决了optaPlanner的一个问题,其中有一个规划变量和一个规划实体,但是现在在我们的项目中有很多规划变量的需求,比如我们要找到最好的房间(容量,isAC等),汽车(totalSeatsLeft,isAC等),我们不知道有多少资源,因为我们每天都需要根据用户的需求增加更多的资源,比如会议室设施等,所以给我一些想法,这样我们就可以为optaPlanner做一个域。多谢了。

  • 各位opatplanner用户, 我的规划问题是:获取遥感卫星星座的有效时间表。 @PlanningEntity: @PlanningVariable: 我的问题数据主要是这样的: Image_Strip: D1 Sat2 22-12-2015 11:02:24.051 D1 Sat1 22-12-2015 11:04:24.122 A2 Sat3 22-12-2015 11:06:24.172

  • 在制定时间表时,你必须遵守法律(硬性要求),该法律规定,作为一名员工,你每七天只能工作一定的时间。它没有说日历周的原因是在创建时间表时为雇主提供一些回旋空间(通常是提前4-16周)。一旦设置了此计划期的开始日期,在您想要进行完整的重新规划之前,该日期无法更改,但您需要通知员工。所以它可以被视为一个变量,直到你接受了时间表,然后它就变成了一个常数。当然,这是每个员工的个人情况。该开始日期将由您的第一

  • 我正在尝试限制可以与特定实体关联的计划变量。在 OptaPlanner 手册的第 4.3.4.2.2 节中,显示了一个示例,但不清楚应该如何生成变量列表。列表应包含哪些内容?这些计划变量本身吗?它们可以是副本吗?如果允许复制,那么如何比较它们?如果不是,则在定义计划实体时计划变量不在范围内 - 我意识到这是一个 Java 问题,但如何从计划实体定义访问计划变量列表并不明显。 这是早期版本不支持的6

  • 我正在使用Optaplanner解决一个类似于病人入院调度示例的问题。 我面临两个问题。 首先,当一个规划实体(类似于示例中的bedDesignation)被某人(而不是optaplanner)定位时,该规划实体像其他实体一样被打分。手工放置的计划实体变为不可移动的计划实体,但仍被打分为可移动的计划实体。正因为如此,它打破了一些硬性的限制。 BedDesignationPillarPartSwap