如何启用可空InverseRelationShadowVariable或避免分配无效订单
问题解决方案
核心问题分析
你当前的约束逻辑存在错误,导致OptaPlanner为了规避硬惩罚,不得不将无法处理的订单强行分配给机器:
- 原约束同时惩罚未分配订单(machine为null)和分配给无效机器两种情况,这让OptaPlanner陷入两难——无论订单是否分配都会触发硬惩罚,因此它会选择分配(哪怕无效)来尝试优化,这与你的需求相悖。
- 另外,全局的
ValueRangeProvider给所有机器开放了全部订单的可选范围,机器可以任意选择订单,即使自身无法处理,进一步增加了无效分配的概率。
具体解决步骤
1. 修正约束逻辑
只惩罚已分配但机器无法处理的订单,允许订单处于未分配状态(machine为null):
private Constraint orderOnCorrectMachine(ConstraintFactory constraintFactory) { return constraintFactory .forEach(Order.class) // 仅过滤:已分配机器,但机器无法处理该订单的情况 .filter(order -> order.getMachine() != null && !order.isValidMachine()) .penalize(HardSoftScore.ONE_HARD) .asConstraint("Order must be assigned to a valid machine"); }
这样调整后,未分配的订单不会被惩罚,OptaPlanner就不会强行分配无法处理的订单。
2. 限制机器可选订单范围(推荐)
从根源减少无效分配的可能,给每个机器的PlanningListVariable设置仅能选择它能处理的订单:
- 在
Machine类中添加机器专属的订单范围提供者,并绑定到PlanningListVariable:
@PlanningEntity public class Machine { private List<Order> m_plannedOrders; // 为当前机器提供仅能处理的订单作为可选范围 @ValueRangeProvider(id = "machineSpecificOrderRange") public List<Order> getAvailableOrders(List<Order> allOrders) { return allOrders.stream() .filter(order -> canManage(order.getItemCode())) .collect(Collectors.toList()); } @PlanningListVariable(valueRangeProviderRefs = "machineSpecificOrderRange") public List<Order> getPlannedOrders() { return m_plannedOrders; } // 其他原有方法不变 }
- 保留
MachineOrdersPlanning类中的全局订单事实集合,供机器的范围提供者调用:
@PlanningSolution public class MachineOrdersPlanning { private List<Machine> m_machines; private List<Order> m_orders; private HardSoftScore m_score; @PlanningEntityCollectionProperty public List<Machine> getMachines() { return m_machines; } @ProblemFactCollectionProperty public List<Order> getOrders() { return m_orders; } @PlanningScore public HardSoftScore getScore() { return m_score; } // 其他setter/getter方法 }
调整后,每个机器的可选订单列表仅包含自身能处理的订单,从根本上避免了无效分配的可能。
3. 优化订单有效性判断逻辑
确保Order类的isValidMachine()逻辑符合需求:
public boolean isValidMachine() { if (m_machine == null) { // 未分配的订单无需验证有效性 return true; } return m_machine.canManage(m_itemCode); }
额外可选配置
如果需要鼓励优先分配可处理的订单,但不强制分配无法处理的订单,可以添加一个软约束:
private Constraint unassignedOrder(ConstraintFactory constraintFactory) { return constraintFactory .forEach(Order.class) .filter(order -> order.getMachine() == null) .penalize(HardSoftScore.ONE_SOFT) .asConstraint("Prefer assigned orders"); }
内容的提问来源于stack exchange,提问作者StefanoM
相关产品推荐
相关产品推荐

