使用Pyomo实现不同容量分箱的资产约束分配及代码纠错
代码错误根因
分箱超容量问题由3处核心逻辑错误导致:
- 容量约束计算逻辑错误:约束中仅统计了放入分箱的资产条目数,没有乘以
value_asset字典存储的每个资产实际规模,本质是限制分箱内资产个数不超容量,完全没有约束资产总规模。 - 决策变量定义错误:
x[asset, b]是标记「资产是否放入对应分箱」的0-1变量,原代码定义为无上限非负整数,变量可以取大于1的数值,会直接突破约束限制。 - 单资产分配约束不严:原有约束写为
sum x <=1,仅限制资产最多放入1个分箱,未强制资产必须完成分配,和全量资产分配的业务要求不匹配。 - 依赖导入缺失:原代码仅导入了
SolverFactory,没有导入Pyomo核心建模模块,运行会直接报名称错误。
修正后可运行代码
import pyomo.environ as pyo from pyomo.opt import SolverFactory value_asset = {'J': 2, 'B': 4, 'D': 18, 'C': 34, 'A': 20, 'E': 31} bins = {'y1': 50, 'y2': 20, 'y3': 30, 'y4': 70, 'y5': 40} Assets = {'A': ['y1', 'y2'], 'J': ['y1', 'y2'], 'E': ["y4", "y5"], 'B': ["y4", "y5"], 'D': ['y5', "y4", "y3"], 'C': ["y1", "y2", 'y3', 'y4', 'y5']} model = pyo.ConcreteModel() model.Assets = pyo.Set(initialize=Assets.keys()) model.budget = pyo.Set(initialize=bins.keys()) # 定义0-1决策变量:1代表资产放入对应分箱,0代表不放 model.x = pyo.Var(model.Assets, model.budget, within=pyo.Binary) model.less_budget = pyo.ConstraintList() # 分箱容量约束:统计分箱内所有资产的总规模,不超过分箱上限 for b in model.budget: model.less_budget.add( expr=sum(model.x[asset, b] * value_asset[asset] for asset in model.Assets) <= bins[b] ) # 资产可分配范围约束:禁止资产放入不允许的分箱 model.excluded = pyo.ConstraintList() for asset in model.Assets: allowed_bins = Assets[asset] forbidden_bins = list(bins.keys() - allowed_bins) for fb in forbidden_bins: model.excluded.add(expr=model.x[asset, fb] == 0) # 单资产分配约束:每个资产必须且仅能放入1个分箱 model.one_bins = pyo.ConstraintList() for asset in model.Assets: model.one_bins.add(expr=sum(model.x[asset, b] for b in model.budget) == 1) # 目标函数:当前保留原逻辑(最大化成功分配的资产数量) # 如果需要最大化分配的资产总规模,可以替换为注释中的目标写法 model.obj = pyo.Objective( expr=sum(model.x[asset, b] for asset in model.Assets for b in model.budget), sense=pyo.maximize ) # 总规模最大化目标: # model.obj = pyo.Objective( # expr=sum(model.x[asset, b] * value_asset[asset] for asset in model.Assets for b in model.budget), # sense=pyo.maximize # ) solver = pyo.SolverFactory('cbc', executable=r'C:\Users\cc\Downloads\Cbc-2.10-win64-msvc15-md\bin\cbc.exe') solver.solve(model) # 打印分配结果 model.x.display() # 校验每个分箱的实际占用容量 print("\n各分箱实际占用容量:") for b in bins.keys(): used = sum(pyo.value(model.x[a,b]) * value_asset[a] for a in model.Assets) print(f"{b}: 已用{used}/上限{bins[b]}")
代码说明
- 修正后代码严格满足核心业务要求:分箱总规模不超上限、资产仅分配到允许的分箱范围内、每个资产仅分配到1个分箱。
- 代码末尾增加了分箱容量校验逻辑,可以直接打印每个分箱的实际占用情况,方便验证结果正确性。
- 如果业务允许部分资产不分配,只需将单资产分配约束的
==1改回<=1即可。
内容的提问来源于stack exchange,提问作者cyntha
相关产品推荐
相关产品推荐

