OPTAPLANNER技术咨询:能否预定义规划变量的固定值?
在OptaPlanner中固定部分规划变量的值
当然可以,OptaPlanner提供了多种方式实现固定部分规划变量值的需求,以下是两种最常用的方案:
方案一:使用@PlanningPin注解
这是官方推荐的最简单直接的方式,通过标记实体为“固定”,让求解器在优化过程中跳过对其规划变量的修改:
- 在规划实体类中添加一个boolean类型字段,并用
@PlanningPin注解标记 - 当该字段值为
true时,求解器不会修改该实体的任何规划变量 - 示例代码:
@PlanningEntity public class Task { // 规划变量:任务的调度日期 @PlanningVariable(valueRangeProviderRefs = {"dateRange"}) private LocalDate scheduledDate; // 标记该实体是否固定 @PlanningPin private boolean pinned; // 构造方法、Getter、Setter省略 } - 使用时,只需将需要固定的
Task实例的pinned设为true,并预先给scheduledDate赋值为目标日期,再传入求解器即可。优化过程中该任务的调度日期会保持不变。
方案二:自定义移动过滤器(Move Filter)
如果需要更灵活的控制(比如根据复杂业务条件动态判断是否允许修改变量),可以通过实现MoveFilter接口过滤掉修改固定实体的移动操作:
- 实现
MoveFilter接口,在accept方法中判断移动是否涉及固定实体,若涉及则拒绝该移动 - 示例代码:
public class PinnedTaskMoveFilter implements MoveFilter<TaskSchedule> { @Override public boolean accept(ScoreDirector<TaskSchedule> scoreDirector, Move<TaskSchedule> move) { // 处理ChangeMove(单个实体变量修改) if (move instanceof ChangeMove) { ChangeMove<TaskSchedule> changeMove = (ChangeMove<TaskSchedule>) move; Task task = (Task) changeMove.getEntity(); // 只允许修改未固定的任务 return !task.isPinned(); } // 处理SwapMove(实体间变量交换)等其他移动类型,确保不涉及固定任务 if (move instanceof SwapMove) { SwapMove<TaskSchedule> swapMove = (SwapMove<TaskSchedule>) move; Task task1 = (Task) swapMove.getEntity1(); Task task2 = (Task) swapMove.getEntity2(); return !task1.isPinned() && !task2.isPinned(); } return true; } } - 在求解器配置中添加该过滤器,确保求解器只执行符合条件的移动:
<solver> <!-- 其他配置 --> <moveFilterClass>com.example.PinnedTaskMoveFilter</moveFilterClass> </solver>
总结
@PlanningPin适合静态固定场景,配置简单,无需额外编写复杂逻辑- 自定义移动过滤器适合动态或复杂条件的固定需求,灵活性更高
内容的提问来源于stack exchange,提问作者Rayamon
相关产品推荐
相关产品推荐

