英文:
Overconstrained planning not working as expected
问题
我一直在努力使过度约束的规划适用于我的情况,但在一些失败的硬约束仍然被分配的情况下遇到问题。如果之前已经有人提过这个问题,我很抱歉,但我看到的大多数示例/解决方案都围绕着Drools,而我在这个项目中使用的是流API。我正在使用quarkus 1.4.2版本的optaplanner实现,如果这有帮助的话。
以下是我试图实现的一些示例约束:
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结束)。
如果您对我可能做错了什么有任何见解,我会非常感谢,提前谢谢:)
英文:
I've been trying to get over-constrained planning to work for my situation, but keep running into issues where some failed hard constraints are still being assigned. Apologies if this has been answered before, but most examples/solutions I have seen are centered around Drools, and I'm using the streams API on this project. Using the quarkus 1.4.2 implementation of optaplanner, if that helps.
Below are some example constraints of what I'm trying to accomplish:
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 is a simple local function to get the absolute difference between two numbers)
Note that these both work independently of each other in terms of honoring the nullable planning variable - it's only when both are enabled that I am getting unexpected results. When both are enabled, the one with the lower hard score is still assigned in the solution despite showing up as a hard constraint in the debug log (which in my local testing always finishes at -12hard/-2medium/0soft).
Any insight on what I might be doing wrong would be much appreciated, and thanks in advance
答案1
得分: 0
作为后续,我的任务冲突约束中的 Joiners.lessThan(Assignment::getId)
部分似乎与可空的任务分配不兼容。我将其移除,并添加了一些更明确的检查,现在一切都正常工作了
以下是为可能有帮助的任何人进行的伪代码调整:
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));
}
英文:
As a follow up, it appears the Joiners.lessThan(Assignment::getId)
portion of my assignment conflict constraint is not compatible with nullable assignments. I removed that and added some more explicit checks instead, and now things are working like they should
psuedo-adaptation for anyone it might help:
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));
}
答案2
得分: 0
第一个约束条件难道不应该是 fromUnfiltered(Assignment.class)
而不是 from(Assignment.class)
吗?我认为 from()
不会传递未分配计划变量的实体,因此 ONE_MEDIUM 惩罚永远不会被应用吗?
英文:
Doesn't the first constraint have to be a fromUnfiltered(Assignment.class)
rather than from(Assignment.class)
. I believe that from()
does not pass entities with unassigned planning variables hence the ONE_MEDIUM penalty would never be applied?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论