Optaplanner - CVRP - 返回中途停留的仓库

时间:2016-10-28 14:55:03

标签: java optaplanner

我的问题是CVRP的修改,最终也将包括时间窗口。由于时间窗口已经嵌入到示例中,因此我不应该太难理解它们。但是,我需要更改CVRP示例的核心约束之一,并且我对如何执行此操作感到有点迷失。

在我尝试建模的系统中,车辆可以离开其仓库,转到几个不同的客户,并加载材料。但是,我的模型与示例的不同之处在于,车辆可以访问任何Depot中链以存入其当前负载。

我一直在查看文档,试图弄清楚如何做到这一点,到目前为止我的基本理解是我必须更改Depot的定义(可能通过实现Standstill)能够成为车辆访问的一系列地方的一部分,和/或可能只是将Depot整合到客户中,并采用某种特殊规则,即访问车站会清空车辆而不是增加需求。我也一直在关注影子变量和可变听众,但我不知道这是否是正确的方法。这有点令人困惑。

任何人都可以提供一些提示或建议,或者在我将自己挖到一个洞之前指出我在哪里开始的正确方向?

1 个答案:

答案 0 :(得分:0)

根据杰弗里(Geoffrey)的建议,将您的Vehicle类重命名为VehicleTrip,并为其赋予一个值previousVehicleTrip,使其指向上一个和下一个旅行。和nextVehicleTrip,并为其提供可变的开始时间和结束时间(Kotlin中的代码示例):

class VehicleTrip(
    ...,
    var startTime: LocalDateTime? = null,
    var endTime: LocalDateTime? = null,
    val previousVehicleTrip?: VehicleTrip = null,
    val nextVehicleTrip?: VehicleTrip = null
) : Standstill {
    ...
}

您可以在启动VehicleTrips时设置这些值。当您基于StackOverFlowError获得VehicleTrip.hashCode()时,只需覆盖hashCode()类的VehicleTrip函数。 (也许有人对此有更好的建议?)

更新阴影变量。

Customer类中,应该有一个变量arrivalTime(类似于CVRPTW示例),它是一个自定义阴影变量。在此变量的侦听器类中,通常只更新车辆在客户处的到达时间,以及在此行程中接下来到达的客户的到达时间。现在,您还需要更新当前客户出差之后的所有出差时间。

例如,您可能有两次旅行VT1VT2,并且有三个客户C1C2C3。从

更改时
VT1 - C1 - VT2 - C2 - C3

VT1 - C2 - C1 - VT2 - C3

您想要更新的东西是(按顺序)

  1. C2.arrivalTime
  2. C1.arrivalTime
  3. VT1.endTime
  4. VT2.startTime
  5. C3.arrivalTime
  6. VT2.endTime

请注意,在TimeWindowedCustomer示例中,变量侦听器仅执行步骤1和2.。因此,我们必须添加步骤3至6。

为此,请在@CustomShadowVariable的开始和结束时间添加VehicleTrip批注(并且不要忘记将VehicleTrip标记为计划实体),该注释使用与时间窗口客户相同的变量侦听器类:

class VehicleTrip(
   ...,
   @CustomShadowVariable(
        variableListenerRef = PlanningVariableReference(
            entityClass = TimeWindowedCustomer::class, 
            variableName = "arrivalTime"
        ))
   var startTime: LocalDateTime? = null,
   ...
) : Standstill {
    ...
}

现在在ArrivalTimeUpdatingVariableListener类中,您可以添加步骤3.到6.,类似于步骤1.和2.的实现方式。确保保留更新这些变量的顺序,并在使用ScoreDirectorbeforeVariableChanged()方法更改变量时通知afterVariableChanged()