optaplanner罚款不适用于无效变量
我正在使用两个计划变量的optaplanner,其中一个用nullable = true定义。 在会议示例(为简单起见)之后,说房间可能是无效的,但时间不能为空。
我定义了对非编号的约束,time
变量,但似乎只有在可用room
变量的变量不是零的情况下,惩罚才能有效,否则会失败。
以下是我的代码的片段:
@PlanningEntity
public class Meeting {
@PlanningVariable(valueRangeProviderRefs = "time")
private LocalDateTime time;
@PlanningVariable(valueRangeProviderRefs = "availableRooms", nullable = true)
private Room room;
private long personId;
...
}
在我的约束提供商类中,我定义了以下约束,以确保一个人不能参加两个单独的会议:
protected Constraint samePersonAndTimeConflict(ConstraintFactory constraintFactory) {
return constraintFactory
// Select each pair of 2 different meetings ...
.forEachUniquePair(Meeting.class,
// ... for the same person ...
equal(Meeting::getPersonId),
// ... in the same time ...
equal(Meeting::getDateTime))
// ... and penalize each pair with a hard weight.
.penalize(SAME_PERSON_AND_TIME_CONFLICT, HardSoftScore.ONE_HARD);
}
创建两个具有非零值的对象时,此约束将正常工作并罚款如果应该同时同时参加两个单独的会议,则有一个硬得分。但是,当使用可确定的房间变量的对象时,确实没有惩罚。结果是,我留下了一个解决方案,其中许多实例对同一个人的分配相同。
我也尝试以其他方式操纵约束,例如使用“ foreachincludingnullvars”和“ foreach”,但是我看到了相同的结果:
protected Constraint samePersonAndTimeConflict(ConstraintFactory constraintFactory) {
return constraintFactory
.forEachIncludingNullVars(Meeting.class)
//.filter(meeting -> meeting.getDateTime() != null)
.join(Meeting.class,
lessThan(Meeting::getId),
equal(Meeting::getTime),
equal(Meeting::getPersonId)) //,
.penalize(SAME_PERSON_AND_TIME_CONFLICT, HardSoftScore.ONE_HARD);
我也尝试将分数类更改为hardmediumsoftScore
并通过One_Medium
进行惩罚。对于与空房间的会议,仍然没有处罚。
似乎Optaplanner根本无法正常工作。 在这一点上,我不知道我还能尝试什么。请指教。
***编辑***
按照以下建议使用嵌套的constraintFactory
添加了附加foreachincludingnullvars
条款,我最终按照以下方式实现了我的约束 - 它现在起作用:
protected Constraint samePersonAndTimeConflict(ConstraintFactory constraintFactory) {
final Constraint constraint = constraintFactory.forEachIncludingNullVars(Meeting.class)
.join(
constraintFactory.forEachIncludingNullVars(Meeting.class)
.filter(meeting -> meeting.getTime() != null),
lessThan(WorkDay::getId),
equal(WorkDay::getEmployeeId),
equal(WorkDay::getDate))
.penalize("Same person and time conflict", HardMediumSoftScore.ONE_HARD);
return constraint;
}
I am using OptaPlanner with two planning variables, one of them defined with nullable=true.
Following a Meeting example (for simplicity), say the Room could be null but the Time can't be null.
I defined a constraint on the non-null, time
variable, but it seems that a penalty only works when the nullable room
variable is not null, and fails otherwise.
Below is is snippet of my code:
@PlanningEntity
public class Meeting {
@PlanningVariable(valueRangeProviderRefs = "time")
private LocalDateTime time;
@PlanningVariable(valueRangeProviderRefs = "availableRooms", nullable = true)
private Room room;
private long personId;
...
}
In my Constraint Provider class, I defined the following constraint for making sure one person can't be at two separate meetings:
protected Constraint samePersonAndTimeConflict(ConstraintFactory constraintFactory) {
return constraintFactory
// Select each pair of 2 different meetings ...
.forEachUniquePair(Meeting.class,
// ... for the same person ...
equal(Meeting::getPersonId),
// ... in the same time ...
equal(Meeting::getDateTime))
// ... and penalize each pair with a hard weight.
.penalize(SAME_PERSON_AND_TIME_CONFLICT, HardSoftScore.ONE_HARD);
}
When creating two objects with non-null values, this constraint will work fine and penalize with one hard score if the same person is supposed to be in two separate meetings at the same time. However, when working with an object for which the nullable room variable is indeed null- there is no penalty. The outcome is that I am left with a solution in which many instances have the same time assignment for the same person.
I tried manipulating the constraint in other ways as well, such as using the "forEachIncludingNullVars" and the "forEach", but I'm seeing the same result:
protected Constraint samePersonAndTimeConflict(ConstraintFactory constraintFactory) {
return constraintFactory
.forEachIncludingNullVars(Meeting.class)
//.filter(meeting -> meeting.getDateTime() != null)
.join(Meeting.class,
lessThan(Meeting::getId),
equal(Meeting::getTime),
equal(Meeting::getPersonId)) //,
.penalize(SAME_PERSON_AND_TIME_CONFLICT, HardSoftScore.ONE_HARD);
I also tried changing the score class to the HardMediumSoftScore
and penalize by ONE_MEDIUM
. Still no penalty for meetings with null rooms.
It seems that OptaPlanner is simply not working as it should.
At this point I don't know what else I can try. Please advise.
*** Editing ***
Following the advice below for using a nested constraintFactory
with an additional forEachIncludingNullVars
clause, I ended up implementing my constraint as follows - and it now works:
protected Constraint samePersonAndTimeConflict(ConstraintFactory constraintFactory) {
final Constraint constraint = constraintFactory.forEachIncludingNullVars(Meeting.class)
.join(
constraintFactory.forEachIncludingNullVars(Meeting.class)
.filter(meeting -> meeting.getTime() != null),
lessThan(WorkDay::getId),
equal(WorkDay::getEmployeeId),
equal(WorkDay::getDate))
.penalize("Same person and time conflict", HardMediumSoftScore.ONE_HARD);
return constraint;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
foreach()
在这里无法使用,因为这只会为您提供任何变量不为空的实体。foreachincludingNullvars()
是去这里的方式。但是,您还需要了解JOIN
具有与foreach
的行为相同的行为 - 它不包括具有空变量的实体。要考虑到这一点,您需要加入嵌套流,这样:
这样,连接将创建所有实体的交叉产品,无论其任何变量是否为null。然后,它成为
过滤器
的问题,将您不希望看到空的部分。forEach()
will not work here, as that will only give you entities where none of the variables are null.forEachIncludingNullVars()
is the way to go here. But you also need to understand thatjoin
has the same behavior asforEach
- it does not include entities with null variables.To take that into account, you need to join with a nested stream, like so:
This way, the join will create a cross-product of all entities, regardless of whether any of their variables are null or not. It then becomes a question of
filter
ing out the parts where you do not wish to see nulls.