带有分数的 VRP 依赖于 optaplanner 中的多个作业
VRP with score dependens on more than one job in optaplanner
我们正在尝试使用 Optaplanner 求解 VRP。
分数计算通过约束流运行。
现在我有两辆车(A 和 B),想安排两个工作(J1 和 J2)。
构造启发式 (FIRST_FIT_DECREASING) 将 J1 调度到 A 并将 J2 调度到 B,到目前为止正确的是什么。
现在这两个工作也有一个属性“客户”,如果两个工作的客户相同但车辆不同,我想分配一个惩罚。
为此,我在 ConstraintProvider 中创建了一个约束条件,它通过 groupBy 过滤所有具有相同客户但不同车辆的作业。
如果我现在打开FULL_ASSERT_MODE,调度J2后会出现IllegalStateException,因为增量计算的分数与完整计算的分数不同。
我怀疑这是因为重新计算作业时间的 VariableListener 仅告知 ScoreDirector 关于我的影子变量的作业 J2 的更改,因此仅更改与其相关的分数部分。
如何告诉 Optaplanner J1 的分数也必须重新计算?我无法通过 VariableListener 到达作业 J1 以告诉 ScoreDirector 必须在此处更改分数。
或者这个问题需要不同的方法吗?
这是一个有点难以完全解释的问题。 TLDR 版本:约束流仅对来自 from()
、join()
或 ifExists()
的对象更改做出反应。未通过这些语句进行的对象更改将不会被捕获,因此会导致分数损坏。下面是更长的解释。
考虑这样一个假设的约束流:
constraintFactory.from(Shift.class)
.join(Shift.class)
.filter((shift1, shift2) -> shift1.getEmployee() == shift2.getEmployee())
...
此约束流将正常工作,因为如果您通过设置不同的员工来更改 Shift
,将重新评估 Shift
。他们通过 from()
和 join()
进入流,这就是 CS 知道在他们改变时重新评估 Shifts
的方式。
现在考虑这个约束流:
constraintFactory.from(Shift.class)
.filter(shift -> shift.getEmployee().getName() == "Lukas")
...
如果 Shift
发生变化,将重新评估此约束流。但是当Employee
的name
改变时,约束流不会重新求值; Employee
既不在 from()
中也不在 join()
中,对 Employee
的更改不会触发约束流的重新评估。
在您的特定情况下,您需要确保几件事:
- 可变侦听器将实际更改的所有内容标记为已更改。
- 如果您修改问题事实,则需要确保您的变量侦听器也处理该问题。
- 您希望约束流做出反应的对象正在通过
from()
或 join()
进入。
我们正在尝试使用 Optaplanner 求解 VRP。 分数计算通过约束流运行。
现在我有两辆车(A 和 B),想安排两个工作(J1 和 J2)。 构造启发式 (FIRST_FIT_DECREASING) 将 J1 调度到 A 并将 J2 调度到 B,到目前为止正确的是什么。
现在这两个工作也有一个属性“客户”,如果两个工作的客户相同但车辆不同,我想分配一个惩罚。
为此,我在 ConstraintProvider 中创建了一个约束条件,它通过 groupBy 过滤所有具有相同客户但不同车辆的作业。
如果我现在打开FULL_ASSERT_MODE,调度J2后会出现IllegalStateException,因为增量计算的分数与完整计算的分数不同。 我怀疑这是因为重新计算作业时间的 VariableListener 仅告知 ScoreDirector 关于我的影子变量的作业 J2 的更改,因此仅更改与其相关的分数部分。
如何告诉 Optaplanner J1 的分数也必须重新计算?我无法通过 VariableListener 到达作业 J1 以告诉 ScoreDirector 必须在此处更改分数。
或者这个问题需要不同的方法吗?
这是一个有点难以完全解释的问题。 TLDR 版本:约束流仅对来自 from()
、join()
或 ifExists()
的对象更改做出反应。未通过这些语句进行的对象更改将不会被捕获,因此会导致分数损坏。下面是更长的解释。
考虑这样一个假设的约束流:
constraintFactory.from(Shift.class)
.join(Shift.class)
.filter((shift1, shift2) -> shift1.getEmployee() == shift2.getEmployee())
...
此约束流将正常工作,因为如果您通过设置不同的员工来更改 Shift
,将重新评估 Shift
。他们通过 from()
和 join()
进入流,这就是 CS 知道在他们改变时重新评估 Shifts
的方式。
现在考虑这个约束流:
constraintFactory.from(Shift.class)
.filter(shift -> shift.getEmployee().getName() == "Lukas")
...
如果 Shift
发生变化,将重新评估此约束流。但是当Employee
的name
改变时,约束流不会重新求值; Employee
既不在 from()
中也不在 join()
中,对 Employee
的更改不会触发约束流的重新评估。
在您的特定情况下,您需要确保几件事:
- 可变侦听器将实际更改的所有内容标记为已更改。
- 如果您修改问题事实,则需要确保您的变量侦听器也处理该问题。
- 您希望约束流做出反应的对象正在通过
from()
或join()
进入。