过度约束的计划未按预期工作

Overconstrained planning not working as expected

我一直在努力让过度约束的计划适合我的情况,但让 运行 解决仍在分配一些失败的硬约束的问题。抱歉,如果之前有人回答过这个问题,但我看到的大多数 examples/solutions 都以 Drools 为中心,我在这个项目中使用流 API。使用 optaplanner 的 quarkus 1.4.2 实现,如果有帮助的话。

以下是我要完成的一些限制示例:

private Constraint unnassignedPerson(ConstraintFactory constraintFactory) {
    return constraintFactory.from(Assignment.class)
            .filter(assignment -> assignment.getPerson() == null)
            .penalize("Unassigned", HardMediumSoftScore.ONE_MEDIUM);

private Constraint numberAssignmentConflict(ConstraintFactory constraintFactory) {
    return constraintFactory.from(Assignment.class)
            .join(Assignment.class,
                    Joiners.equal(Assignment::getPerson),
                    Joiners.equal(Assignment::getNumber),
                    Joiners.lessThan(Assignment::getId))
            .penalize("Number Conflict", HardMediumSoftScore.of(2, 0, 0));

private Constraint tooLittleSpaceBetweenResourceAssignment(ConstraintFactory constraintFactory) {
    return constraintFactory.from(Assignment.class)
            .join(Assignment.class, Joiners.equal(Assignment::getPerson), Joiners.lessThan(Assignment::getId))
            .filter((assignment, assignment2) -> !assignment.getResourceId().equals(assignment2.getResourceId()))
            .filter(((assignment, assignment2) -> inRange(1, assignment.getNumber(), assignment2.getNumber())))
            .penalize("Not enough space between assignments of different resource (requires 1)", HardMediumSoftScore.of(1, 0, 0));
}

(inRange 是一个简单的局部函数,用于获取两个数字之间的绝对差值)

请注意,在遵守可为空的计划变量方面,这两者彼此独立工作 - 只有当两者都启用时,我才会得到意想不到的结果。当两者都启用时,尽管在调试日志中显示为硬约束(在我的本地测试中总是以 -12hard/-2medium/0soft 结束),但硬分值较低的仍然在解决方案中分配。

任何关于我可能做错了什么的见解都将不胜感激,并提前致谢:)

作为后续行动,我的分配冲突约束的 Joiners.lessThan(Assignment::getId) 部分似乎 与可为 null 的分配兼容。我删除了它并添加了一些更明确的检查,现在一切正常了:D

对任何可能有帮助的人的伪适应:

private Constraint numberAssignmentConflict(ConstraintFactory constraintFactory) {
    return constraintFactory.from(Assignment.class)
            .join(Assignment.class,
                    Joiners.equal(Assignment::getPerson),
                    Joiners.equal(Assignment::getNumber))
            .filter(((assignment, assignment2) -> assignment.getPerson() != null && assignment2.getPerson() != null))
            .filter(((assignment, assignment2) -> !assignment.getId().equals(assignment2.getId())))
            .penalize("Number Conflict", HardMediumSoftScore.of(2, 0, 0));
}

第一个约束是否必须是 fromUnfiltered(Assignment.class) 而不是 from(Assignment.class)。我相信 from() 不会传递具有未分配计划变量的实体,因此永远不会应用 ONE_MEDIUM 惩罚?