【问题标题】:VRP with score dependens on more than one job in optaplanner有分数的 VRP 依赖于 optaplanner 中的不止一项工作
【发布时间】:2021-08-09 15:42:36
【问题描述】:

我们正在尝试使用 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 必须在此处更改分数。

或者这个问题需要不同的方法吗?

【问题讨论】:

    标签: optaplanner vehicle-routing


    【解决方案1】:

    这是一个很难完全解释的问题。 TLDR 版本:约束流仅对来自from()join()ifExists() 的对象的更改作出反应。未通过这些语句的对象的更改将不会被捕获,因此会导致分数损坏。接下来是更长的解释。

    考虑如下假设的约束流:

    constraintFactory.from(Shift.class)
        .join(Shift.class)
        .filter((shift1, shift2) -> shift1.getEmployee() == shift2.getEmployee())
        ...
    

    这个约束流可以正常工作,因为如果您通过设置不同的员工来更改ShiftShifts 将被重新评估。它们通过from()join() 进入流,这就是CS 知道在它们发生变化时重新评估Shifts 的方式。

    现在考虑这个约束流:

    constraintFactory.from(Shift.class)
        .filter(shift -> shift.getEmployee().getName() == "Lukas")
        ...
    

    如果Shift 发生更改,将重新评估此约束流。但是当Employeename发生变化时,约束流不会被重新评估; Employee 既不在from() 也不在join() 中,对Employee 的更改不会触发对约束流的重新评估。

    在您的特定情况下,您需要确保几件事:

    • 可变侦听器将所有实际更改的内容标记为已更改。
    • 如果您修改问题事实,您需要确保您的变量侦听器也能处理它。
    • 您希望约束流对其做出反应的对象通过from()join() 进入。

    【讨论】:

      猜你喜欢
      • 2019-02-14
      • 2019-02-09
      • 2021-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多