OptaPlanner装箱方案结果非最优,求代码问题排查指导
问题排查与优化方案
核心问题分析
你的OptaPlanner结果未达到OR-Tools的最优水平,主要原因集中在约束目标设置、初始解策略、搜索时间配置三个方面,以下是具体问题和修正方案:
1. 软约束逻辑偏差(关键问题)
当前软约束computerCost虽意图最小化总容积,但存在两个缺陷:
- 若容器池包含Medium类型,Solver未优先选择大容器(总容积更低),原因是约束权重未体现大容器的优势:使用1个Medium的总容积比2个Small更低,但当前惩罚逻辑下大容器的单容器惩罚值更高,导致Solver倾向于选择更多小容器。
- 未激励容器的容积/重量利用率,导致部分容器空间浪费严重(如你的结果中多个Small容器重量利用率仅20%-30%)。
修正方案:
调整软约束,同时实现最小化总使用容积和最大化容器利用率:
public class CartonizationConstraintProvider implements ConstraintProvider { @Override public Constraint[] defineConstraints(ConstraintFactory constraintFactory) { return new Constraint[]{ requiredWeightTotal(constraintFactory), requiredVolumeTotal(constraintFactory), minimizeTotalUsedVolume(constraintFactory), maximizeVolumeUtilization(constraintFactory), maximizeWeightUtilization(constraintFactory) }; } // 原硬约束保留 Constraint requiredWeightTotal(ConstraintFactory constraintFactory) { return constraintFactory.forEach(OrderItem.class) .groupBy(OrderItem::getContainer, sum(OrderItem::getWeight)) .filter((container, requiredWeight) -> requiredWeight > container.getMaxWeight()) .penalize(HardSoftScore.ONE_HARD, (container, requiredWeight) -> requiredWeight - container.getMaxWeight()) .asConstraint("requiredWeightTotal"); } Constraint requiredVolumeTotal(ConstraintFactory constraintFactory) { return constraintFactory.forEach(OrderItem.class) .groupBy(OrderItem::getContainer, sum(OrderItem::getVolume)) .filter((container, requiredVolume) -> requiredVolume > container.getMaxVolume()) .penalize(HardSoftScore.ONE_HARD, (container, requiredVolume) -> requiredVolume - container.getMaxVolume()) .asConstraint("requiredVolumeTotal"); } // 最小化已使用容器的总容积,提高权重让Solver优先关注 Constraint minimizeTotalUsedVolume(ConstraintFactory constraintFactory) { return constraintFactory.forEach(CartonContainer.class) .ifExists(OrderItem.class, equal(Function.identity(), OrderItem::getContainer)) .penalize(HardSoftScore.ofSoft(100), CartonContainer::getMaxVolume) .asConstraint("minimizeTotalUsedVolume"); } // 最大化容器容积利用率(奖励填满容器) Constraint maximizeVolumeUtilization(ConstraintFactory constraintFactory) { return constraintFactory.forEach(OrderItem.class) .groupBy(OrderItem::getContainer, sum(OrderItem::getVolume)) .filter((container, usedVolume) -> usedVolume > 0) .reward(HardSoftScore.ofSoft(1), (container, usedVolume) -> usedVolume) .asConstraint("maximizeVolumeUtilization"); } // 最大化容器重量利用率(奖励填满容器) Constraint maximizeWeightUtilization(ConstraintFactory constraintFactory) { return constraintFactory.forEach(OrderItem.class) .groupBy(OrderItem::getContainer, sum(OrderItem::getWeight)) .filter((container, usedWeight) -> usedWeight > 0) .reward(HardSoftScore.ofSoft(1), (container, usedWeight) -> usedWeight) .asConstraint("maximizeWeightUtilization"); } }
2. 初始解策略低效
CloudBalance示例的默认初始解策略是随机分配,对于装箱问题效率极低。建议使用**递减最佳适应(Best Fit Decreasing)**生成初始解,让Solver从更优的起点开始搜索。
修正方案:
在SolverConfig中添加构造启发式配置:
SolverFactory<CartonizationSolution> solverFactory = SolverFactory.create(new SolverConfig() .withSolutionClass(CartonizationSolution.class) .withEntityClasses(OrderItem.class) .withConstraintProviderClass(CartonizationConstraintProvider.class) // 配置高效初始解策略 .withConstructionHeuristicConfig(new ConstructionHeuristicConfig() .withConstructionHeuristicType(ConstructionHeuristicType.BEST_FIT_DECREASING)) .withTerminationConfig(new TerminationConfig().withUnimprovedSecondsSpentLimit(15L)));
3. 搜索时间不足
当前设置的withUnimprovedSecondsSpentLimit(5L)仅给了5秒无改进终止时间,对于装箱这类组合优化问题,时间太短。OptaPlanner的元启发式算法需要更多时间探索解空间。
修正方案:
延长无改进时间,同时添加总时间限制:
.withTerminationConfig(new TerminationConfig() .withUnimprovedSecondsSpentLimit(15L) .withSecondsSpentLimit(60L)) // 最多运行60秒,避免无限等待
4. 其他潜在问题
- 容器池完整性:确认
load()方法加载的CartonRange包含Medium类型容器,若初始数据中没有Medium容器,OptaPlanner无法使用该类型。 - 分数解释错误:你的代码中
scoreManager.explainScore(solution)使用的是初始解solution,而非求解后的solvedSolution,改为solvedSolution才能查看最优解的分数细节,帮助排查约束问题:ScoreExplanation<CartonizationSolution, HardSoftScore> explanation = scoreManager.explainScore(solvedSolution); System.out.println(scoreManager.getSummary(solvedSolution));
内容的提问来源于stack exchange,提问作者user2330818
相关产品推荐
相关产品推荐

