Optaplanner Drools规则如何仅处罚单个实体并最小化课程间时间间隔
OptaPlanner课程排期间隔优化问题解答
1. 查询课程A最近的前序课程B的实现方案
你可以通过Drools规则的accumulate聚合函数,从所有符合条件的前序课程中筛选出结束时间最靠近A的那一个,避免匹配到所有更早的课程:
- 首先假设你的课程实体类为
Lesson,包含字段:dayOfWeek(上课日期)、startGrain(开始时间粒索引)、endGrain(结束时间粒索引) - 规则匹配逻辑示例:
rule "Minimize gap between lessons" when // 匹配当前课程A $lessonA: Lesson(dayOfWeek != null, startGrain != null, $day: dayOfWeek, $startA: startGrain) // 聚合所有同天、早于A的课程,取最大的结束时间粒,就是最近前序的结束时间 accumulate( Lesson(dayOfWeek == $day, endGrain != null, endGrain < $startA), $lastEndGrain: max(endGrain) ) // 匹配到最近的前序课程B $lessonB: Lesson(dayOfWeek == $day, endGrain == $lastEndGrain) then // 处罚的权重就是两个课程之间的空隔时间粒数:$startA - $lastEndGrain -1 scoreHolder.addSoftConstraintMatch(kcontext, - ($startA - $lastEndGrain - 1)); end
这个逻辑只会匹配到和A最近的一个前序课程,不会触发多余的处罚。
2. 规则匹配多实体时仅处罚单个实体的方法
完全可以,ScoreHolder的addConstraintMatch/addSoftConstraintMatch方法的末尾参数是该处罚关联的实体列表,你只需要传入你想要处罚的单个实体即可。
以你给出的八皇后规则示例为例,要实现仅处罚$queen1,修改如下:
rule "Horizontal conflict" when $queen1: Queen($id : id, row != null, $i : rowIndex) $queen2: Queen(id > $id, rowIndex == $i) then // 仅传入$queen1作为关联实体,处罚只会绑定到$queen1上 scoreHolder.addConstraintMatch(kcontext, -1, $queen1); end
如果使用OptaPlanner更推荐的Constraint Streams API实现,逻辑会更简洁,不需要编写Drools规则,直接通过Java流操作筛选最近前序、指定处罚关联的实体即可。
内容的提问来源于stack exchange,提问作者Christian
相关产品推荐
相关产品推荐

