如何强制OptaPlanner按1到n的顺序为PlanningVariable赋值
OptaPlanner连续索引分配实现方案
完全可以实现强制连续索引分配的需求,核心可以通过硬约束+变量配置组合落地,常用的两种实现方案如下:
方案1:新增最高优先级硬约束惩罚索引空缺
该方案不需要调整现有模型结构,仅在约束规则里添加两条最高优先级的硬约束即可:
- 首先惩罚重复索引:只要同一个索引被分配给多个任务,就按重复次数乘以超大硬约束权重惩罚
- 其次惩罚索引空缺:统计所有已分配索引的最大值,与总任务数做差值比对,只要最大值大于总任务数,就按差值乘以超大硬约束权重惩罚
以上规则可以保证最终得到的索引必然是1到n的连续无空缺序列,你需要的从1开始累加的计算逻辑自然就具备业务意义。
参考约束代码示例:
Constraint continuousIndexRule(ConstraintFactory constraintFactory) { // 惩罚重复索引 Constraint duplicateIndex = constraintFactory.forEach(Task.class) .groupBy(Task::getIndex, count()) .filter((index, count) -> count > 1) .penalize(HardSoftScore.ONE_HARD, (index, count) -> count - 1) .asConstraint("重复索引硬约束"); // 惩罚索引空缺 Constraint gapIndex = constraintFactory.forEach(Task.class) .groupBy(max(Task::getIndex), count()) .filter((maxIndex, taskCount) -> maxIndex > taskCount) .penalize(HardSoftScore.ONE_HARD, (maxIndex, taskCount) -> maxIndex - taskCount) .asConstraint("索引空缺硬约束"); return duplicateIndex.andThen(gapIndex); }
方案2:使用@PlanningListVariable特性原生支持连续索引
如果是新开发的模型,更推荐直接使用OptaPlanner提供的列表规划变量特性,从根源上避免索引空缺的问题:
- 不需要为每个任务单独定义索引字段,直接在规划解决方案类中定义一个任务列表作为
@PlanningListVariable,列表下标+1就是对应任务的索引 - 列表长度固定等于总任务数n,OptaPlanner求解时只会调整列表中任务的排列顺序,天然保证索引是1到n的连续序列
- 需要计算shadow变量之和时直接遍历列表累加即可,不需要额外做有效性校验,求解效率也比单独分配索引的方案更高
两种方案可以根据你的现有模型改造难度选择:老模型改造成本低选方案1,新模型优先选方案2。
内容的提问来源于stack exchange,提问作者brewphone
相关产品推荐
相关产品推荐

