【问题标题】:Optaplanner - CVRP - returning to depot mid tripOptaplanner - CVRP - 中途返回仓库
【发布时间】:2017-03-11 12:06:29
【问题描述】:

我的问题是对Capacitated Vehicle Routing Problem (CVRP) 的修改,最终也将包含时间窗口

由于 时间窗口 已经内置在示例中,我应该不难弄清楚它们。但是,我需要更改 CVRP 示例的 核心约束 之一,我对如何去做有点迷茫。

我的模特

在我尝试建模的系统中,Vehicle 可以离开它的Depot,转到几个不同的Customers,然后加载材料。但是,我的模型与示例的不同之处在于Vehicle 可以访问任何Depot 中间链来存放其当前负载。

问题

我一直在研究documentation 试图弄清楚如何做到这一点,到目前为止我的基本理解是我必须更改Depot 的定义(也许通过实现Standstill)能够成为车辆访问地点链的一部分,和/或可能只是将Depot 整合到Customer 与某种特殊规则,即访问Depot 会清空车辆而不是增加需求.

我也一直在研究 shadow variablesvariable listeners,但我不知道这是否是正确的方法。这有点令人困惑。

任何人都可以提供一些提示或建议,或者在我把自己挖得太深之前指出正确的方向吗?

【问题讨论】:

  • 将Vehicle类重命名为VehicleTrip,这样一辆车可以做多次旅行吗?如果您有时间窗,则将每个 VehicleTrip 连接到上一个行程(提前固定)。让每辆车行驶 3 次左右。
  • @GeoffreyDeSmet 如果我这样做了,我仍然需要一些方法来连接它们,而且我不确定如何让求解器考虑到这一点。我如何将每个 VehicleTrip 的结束时间链接到另一个的开始时间?同样,我正在考虑一个可变侦听器,但我还没有完全理解那些
  • edit 提出您的问题并提供提到的documentation 的链接。也许一些minimal reproducible example视觉草图模型可以展示您的尝试,并为我们提供指导您的基础。

标签: java optaplanner vehicle-routing


【解决方案1】:

根据 Geoffrey 的建议,将您的 Vehicle 类重命名为 VehicleTrip 并通过赋予其值 previousVehicleTripnextVehicleTrip 使其指向上一个和下一个行程,以及给它一个可变的开始时间和结束时间(Kotlin 中的代码示例):

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

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

更新影子变量。

在您的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 示例中,变量 listener 仅执行步骤 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. 的实现方式。确保保持更新这些变量的顺序,并在使用beforeVariableChanged()afterVariableChanged() 方法更改变量时通知ScoreDirector

【讨论】:

    猜你喜欢
    • 2020-01-24
    • 1970-01-01
    • 2019-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多