我目前有以下设置来解决带取货和退货的 VRP:
A
Vehicle
是一个 PlanningEntity
并且包含 PlanningListVariable
的 LoadJob
实例(PICKUP
或 DROPOFF
):
@PlanningEntity
class Vehicle {
@PlanningId lateinit var planningId: String
@PlanningListVariable lateinit var tour: MutableList<LoadJob>
// ...
}
A
LoadJob
是另一个 PlanningEntity
:
@PlanningEntity
class LoadJob {
@PlanningId lateinit var id: String
@InverseRelationShadowVariable(sourceVariableName = "tour") //
var vehicle: Vehicle? = null
lateinit var location: Location
private set
lateinit var load: Load
private set
// ... more shadow variables and variable listener setup for arrival time follows
}
通过我们当前的设置,我们已经能够在单个车辆上处理多个(子)游览(我们检测
PlanningListVariable
中的循环)。现在,我们还希望能够允许用户将子旅行固定在车辆上。我知道 optaplanner/timefold 目前不支持将变量与 PlanningListVariable
固定在一起。我还知道重构模型以使用链式规划变量可能是一种选择。但是,我认为这可能比我目前正在考虑的方法需要更多工作:
我可以通过将
@PlanningListVariable
移动到新的 Tour
类来使车辆成为规划事实:
@PlanningEntity
class Tour {
@PlanningId lateinit var planningId: String
@PlanningListVariable lateinit var tour: MutableList<LoadJob>
lateinit var earliestStart: OffsetDateTime
lateinit var latestEnd: OffsetDateTime
lateinit var vehicle: Vehicle
// ...
}
并简单地引用
Vehicle
类中的 Tour
。
然后我可以对
Tour
施加限制,因此在规划时会尊重 earliestStart
和 latestEnd
。这样,应该可以为未分配的锁定游览留下时间段(并在我的转换/持久层中删除/添加这些游览)。
所以我的首要问题是:这是一种有效的方法吗? optaplanner/timefold 可以处理这样的模型吗?
后续问题:
groupBy
- 这是正确的方法吗?我担心您正在将模型扩展到以前没有的地方 - 如果不先尝试,我无法对您的问题给出明确的答案;如果不完全复制这个设置,我就无法真正尝试它。
我的建议是尝试您的方法并报告您遇到的问题(如果有)。然后我们可以讨论这些问题是否是我们能够/想要解决的问题。
对于您最初的问题,最通用的答案是肯定的 - 从技术上讲,可以从事实中引用实体,只需仔细检查克隆器是否正常工作即可。可能需要在代码中各处添加
@DeepPlanningClone
。 (FULL_ASSERT
几分钟的环境模式应该足以证明或反驳这一点。)