optaplanner - 有分数的 VRP 依赖于 optaplanner 中的不止一项工作
问题描述
我们正在尝试使用 Optaplanner 解决 VRP。分数计算通过约束流运行。
现在我有两辆车(A 和 B),想安排两个工作(J1 和 J2)。构造启发式 (FIRST_FIT_DECREASING) 将 J1 调度到 A 并将 J2 调度到 B,到目前为止是正确的。
现在这两个工作也有一个属性“客户”,如果两个工作的客户相同但车辆不同,我想分配一个惩罚。
为此,我在 ConstraintProvider 中创建了一个约束,该约束通过 groupBy 过滤所有具有相同客户但不同车辆的作业。
如果我现在打开 FULL_ASSERT_MODE,在调度 J2 之后会发生 IllegalStateException,因为增量计算的分数与完整计算的分数不同。我怀疑这是因为重新计算作业时间的 VariableListener 只告诉 ScoreDirector 我的影子变量对 Job J2 的更改,因此只更改与其相关的分数部分。
我如何告诉 Optaplanner J1 的分数也必须重新计算?我无法通过 VariableListener 到达 Job J1 告诉 ScoreDirector 必须在此处更改分数。
还是这个问题需要不同的方法?
解决方案
这是一个有点难以完全解释的问题。TLDR 版本:约束流仅对来自或from()
的对象的更改做出反应。未通过这些语句的对象的更改将不会被捕获,因此会导致分数损坏。更长的解释如下。join()
ifExists()
考虑这样一个假设的约束流:
constraintFactory.from(Shift.class)
.join(Shift.class)
.filter((shift1, shift2) -> shift1.getEmployee() == shift2.getEmployee())
...
这个约束流可以正常工作,因为如果您Shift
通过设置不同的员工进行更改,Shift
s 将被重新评估。from()
它们通过and进入流join()
,这就是 CS 知道在它们发生变化时重新评估的方式Shifts
。
现在考虑这个约束流:
constraintFactory.from(Shift.class)
.filter(shift -> shift.getEmployee().getName() == "Lukas")
...
Shift
如果发生更改,将重新评估此约束流。但是当name
ofEmployee
发生变化时,约束流不会被重新评估;Employee
既不是 infrom()
也不是 in join()
,对 的更改Employee
不会触发约束流的重新评估。
在您的特定情况下,您需要确保几件事:
- 可变侦听器将所有实际更改的内容标记为已更改。
- 如果你修改问题事实,你需要确保你的变量监听器也能处理它。
- 您希望约束流对其做出反应的对象是通过
from()
或join()
.
推荐阅读
- java - WkHtmlToPdf 库阿拉伯字符平方与斜体字体
- python - 持续的 python/django 错误
- python - 使用 Sticky 时无法调整 Tkinter 按钮的大小
- java - 什么是实现套接字的好方法?
- c# - 使用 WEB/API 进行 C# 依赖注入
- c - 如何使用 for 循环打印存储在变量中的多个值
- php - PHP:将小数点后的数字四舍五入到最接近的5
- swift - 在 SwiftUI 中使用 UIActivityView 分享到 Instagram
- c# - 尝试查找导致回发的控件时使用 Request.Params 返回错误的控件
- r - ggplot中日期X轴标签的精细控制