OptaPlanner基于剩余ProblemFact规划及续瓶分装建模问询
OptaPlanner液体分装场景建模与规划问题解答
问题1:如何让OptaPlanner仅基于剩余ProblemFact进行规划?
由于ProblemFact不可修改,核心思路是基于原ProblemFact创建可变的规划实体副本,仅操作副本的剩余属性,原ProblemFact作为只读参考:
- 保留原始的
LiquidBottle(ProblemFact)类,标记为@ProblemFactProperty,存储瓶子的固定属性(ID、类型、总容积),全程不修改。 - 创建临时规划实体类(比如
LiquidAllocationProxy),关联对应的LiquidBottle,并新增remainingVolume属性(初始值等于原瓶子的总容积),作为OptaPlanner的操作对象。 - 规划过程中,OptaPlanner仅更新
LiquidAllocationProxy的remainingVolume和分配目标箱子,原LiquidBottle的属性始终保持只读状态,实现基于剩余ProblemFact的规划。
问题2:未分装完成的液体瓶建模与续装处理
场景核心建模方式
需要将“分装动作”作为规划实体,而非直接分配整个瓶子,具体类设计如下:
1. ProblemFact类(只读)
LiquidBottle:包含id、liquidType、totalVolume属性,标记@ProblemFactProperty,存储原始瓶子的固定信息。Box:包含id、maxCapacity、allowedLiquidTypes(可选)属性,标记@ProblemFactProperty,作为候选容器。
2. Planning Entity类(可变)
创建LiquidSplitAllocation作为规划实体,代表一次分装操作:
liquidBottle:关联对应的LiquidBottle(只读,参考ProblemFact)targetBox:Planning Variable,类型为Box,表示本次分装的目标箱子allocatedVolume:本次分装的容积,取值范围为0到当前瓶子的剩余容积
3. Planning Solution类
- 包含
List<LiquidBottle>和List<Box>作为ProblemFact集合 - 包含
List<LiquidSplitAllocation>作为Planning Entity集合 - 计算瓶子剩余容积:对每个
LiquidBottle,用totalVolume减去所有关联的LiquidSplitAllocation的allocatedVolume之和,得到未分装的剩余容积。
未完成瓶子的续装处理
不需要手动处理“转到下一个箱子”,通过以下方式让OptaPlanner自动完成:
- 初始化时,为每个
LiquidBottle生成足够数量的LiquidSplitAllocation实体(比如按箱子最大容积预估需要的次数),初始allocatedVolume设为0,targetBox设为null。 - 添加约束规则:
- 每个箱子的所有
allocatedVolume之和不能超过其maxCapacity - 每个
LiquidSplitAllocation的allocatedVolume不能超过对应瓶子的剩余容积 - 分装的液体类型必须符合箱子的
allowedLiquidTypes(如果有类型限制)
- 每个箱子的所有
- OptaPlanner会自动为同一个瓶子分配多个
LiquidSplitAllocation到不同箱子,直到该瓶子的剩余容积为0。
内容的提问来源于stack exchange,提问作者Shi Alexander
相关产品推荐
相关产品推荐

