如何在Optaplanner中停用无需调度的规划实体以缩减搜索空间?
在OptaPlanner中实现非激活任务的规划变量忽略逻辑
要实现当任务active = False时,算法不处理其开始时间和持续时长这两个规划变量、缩小搜索空间,可通过以下几种方式实现:
1. 基于条件的规划变量值域限制
给目标规划变量添加条件式值域,仅当任务处于激活状态时提供有效取值范围;非激活时返回空值域或固定无效值(如null),让算法无法为其生成有效赋值。
代码示例:
// 任务实体类中的开始时间规划变量 @PlanningVariable(nullable = true, valueRangeProviderRefs = {"taskTimeRange"}) public LocalDateTime getStartTime() { return startTime; } // 任务实体类中的持续时长规划变量 @PlanningVariable(nullable = true, valueRangeProviderRefs = {"taskDurationRange"}) public Duration getDuration() { return duration; } // 开始时间的值域提供者,仅激活任务返回有效范围 @ValueRangeProvider(id = "taskTimeRange") public ValueRange<LocalDateTime> getTimeRange() { if (this.active) { // 返回规划窗口内的有效时间范围 return ValueRangeFactory.createLocalDateTimeRange(planningStart, planningEnd); } else { // 非激活任务返回仅包含null的值域,避免算法赋值 return ValueRangeFactory.createSingleton(null); } } // 持续时长的值域提供者,仅激活任务返回有效范围 @ValueRangeProvider(id = "taskDurationRange") public ValueRange<Duration> getDurationRange() { if (this.active) { // 返回允许的时长范围(如1小时到8小时) return ValueRangeFactory.createDurationRange(Duration.ofHours(1), Duration.ofHours(8)); } else { return ValueRangeFactory.createSingleton(null); } }
2. 自定义移动选择器过滤非激活任务
在求解器配置中,通过自定义移动过滤器,让算法仅对激活状态的任务生成修改开始时间和时长的移动操作,彻底排除非激活任务的变量变更搜索。
配置示例(XML):
<solver> <constructionHeuristic> <moveSelector> <filterClass>com.yourpackage.ActiveTaskMoveFilter</filterClass> <changeMoveSelector> <planningVariableName>startTime</planningVariableName> </changeMoveSelector> <changeMoveSelector> <planningVariableName>duration</planningVariableName> </changeMoveSelector> </moveSelector> </constructionHeuristic> <localSearch> <!-- 同样给局部搜索的移动选择器添加过滤器 --> <moveSelector> <filterClass>com.yourpackage.ActiveTaskMoveFilter</filterClass> <changeMoveSelector> <planningVariableName>startTime</planningVariableName> </changeMoveSelector> <changeMoveSelector> <planningVariableName>duration</planningVariableName> </changeMoveSelector> </moveSelector> </localSearch> </solver>
过滤器实现类:
public class ActiveTaskMoveFilter implements MoveFilter<TaskScheduleSolution> { @Override public boolean accept(ScoreDirector<TaskScheduleSolution> scoreDirector, Move<TaskScheduleSolution> move) { // 仅允许修改激活任务的规划变量 if (move instanceof ChangeMove) { ChangeMove<TaskScheduleSolution> changeMove = (ChangeMove<TaskScheduleSolution>) move; Task task = (Task) changeMove.getEntity(); return task.isActive(); } // 其他类型的移动(如交换)也可按需过滤 return false; } }
3. 约束规则中忽略非激活任务
配合上述两种方法,在分数计算的约束规则中仅对激活任务进行校验,避免非激活任务的变量状态影响分数结果。
Drools规则示例:
package com.yourpackage.constraints; import com.yourpackage.Task; import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScoreHolder; global HardSoftScoreHolder scoreHolder; // 仅校验激活任务的时间冲突 rule "NoOverlappingActiveTasks" when $task1: Task(active == true, $start1: startTime, $duration1: duration) $task2: Task(active == true, this != $task1, startTime < $start1.plus($duration1), startTime.plus(duration) > $start1) then scoreHolder.addHardConstraintMatch(kcontext, -1); end
额外注意事项
- 可在任务实体的
setActive方法中添加逻辑:当active设为false时,自动将startTime和duration置为null,确保实体状态一致。 - 若使用OptaPlanner的注解式配置,确保
@PlanningVariable的nullable属性设为true,允许变量为null。
内容的提问来源于stack exchange,提问作者Rayamon
相关产品推荐
相关产品推荐

