我们正在尝试使用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()
传入的