PYOMO整数变量约束问题求助:工厂容量与目标函数约束报错
Pyomo线性规划建模约束问题排查与解决
问题1:工厂容量约束错误分析与解决
首次尝试错误原因
np.count_nonzero是Python数值计算工具,无法转化为Pyomo求解器可识别的线性约束表达式。Pyomo约束必须由Pyomo变量、参数通过代数运算构建,而非直接调用Python数值函数,因此该写法无效。
第二次尝试错误原因
model.Assign定义在select_combos(订单-工厂组合)维度,导致二进制变量数量等于组合总数,当组合规模较大时,触发CPLEX社区版的变量数量限制(社区版通常限制变量数在1000以内)。
解决方案
将Assign变量调整为工厂维度(每个工厂对应1个二进制变量),表示工厂是否启用,大幅减少变量数量;同时根据实际产能定义类型选择约束逻辑:
- 如果产能是工厂总生产能力(单位数):直接约束总生产数量不超过产能与启用状态的乘积(示例采用此逻辑);
- 如果产能是工厂可承接的订单个数:需额外定义订单-工厂级二进制变量,再约束承接订单数不超过产能与启用状态的乘积。
产能约束代码:
def Const6(model,j): # 工厂启用时,总生产数量不超过产能;未启用时总生产为0 return sum(model.x[i,j] for i in model.i if (i,j) in model.select_combos) <= model.s[j] * model.Assign[j] model.consupply=pyo.Constraint(model.j,rule=Const6)
问题2:目标函数防零约束错误分析与解决
错误原因
- 约束函数
Const7仅接收model,i作为参数,但内部引用了未定义的变量j; - 表达式使用生成器对象,而非合法的Pyomo代数表达式;
- 约束索引集为
model.i(订单),但实际需要针对每个订单-工厂组合定义约束。
解决方案
将约束索引集改为model.select_combos,针对每个组合用大M法关联x[i,j]与工厂启用状态,确保x[i,j]>0时工厂处于启用状态:
# 定义大M值,需大于单个订单的最大需求量 M = max(demand.values()) def Const7(model,i,j): # 若工厂j未启用,则x[i,j]必须为0;启用时x[i,j]不超过订单需求上限 return model.x[i,j] <= M * model.Assign[j] model.consplant_binary=pyo.Constraint(model.select_combos,rule=Const7)
修正后的完整代码
import pyomo.environ as pyo # 需求数据 demand= {782912: 808, 782913: 3188, 782914: 2331, 782915: 847, 782916: 2163,789954:5643} # 单位生产成本(修正原代码语法错误) total_costs_per_unit= { (782912, 'PLANT16'): 0.46, (782913, 'PLANT16'): 0.46, (782914, 'PLANT16'): 0.46, (782915, 'PLANT16'): 0.46, (782916, 'PLANT16'): 0.46, (789954,'PLANT05'):0.90, (789954,'PLANT07'):0.91, (789954,'PLANT08'):1.13, (789954,'PLANT10'):0.12 } # 工厂产能(总生产能力,单位数) supply= {'PLANT05': 531,'PLANT07': 841,'PLANT08': 1107,'PLANT10': 981,'PLANT16': 2313} # 构建模型 model=pyo.ConcreteModel() # 集合定义 model.i=pyo.Set(initialize=demand.keys()) # 订单集合 model.j=pyo.Set(initialize=supply.keys()) # 工厂集合 model.select_combos = pyo.Set(within = model.i * model.j, initialize = total_costs_per_unit.keys()) # 参数定义 model.p=pyo.Param(model.select_combos, initialize=total_costs_per_unit) # 单位成本 model.d=pyo.Param(model.i,initialize=demand) # 订单需求量 model.s=pyo.Param(model.j,initialize=supply) # 工厂产能 # 决策变量 model.x=pyo.Var(model.select_combos, within=pyo.NonNegativeReals) # 订单i分配给工厂j的数量 model.Assign=pyo.Var(model.j, domain=pyo.Binary) # 工厂j是否启用(二进制变量) # 目标函数:最小化总成本 model.Obj=pyo.Objective(expr=sum(model.p[i,j]*model.x[i,j] for i,j in model.select_combos),sense=pyo.minimize) # 约束1:订单需求必须满足 def Const1(model,i): return sum(model.x[i,j] for j in model.j if (i,j) in model.select_combos)>=model.d[i] model.condemand=pyo.Constraint(model.i,rule=Const1) # 约束2:工厂产能约束 def Const6(model,j): return sum(model.x[i,j] for i in model.i if (i,j) in model.select_combos) <= model.s[j] * model.Assign[j] model.consupply=pyo.Constraint(model.j,rule=Const6) # 约束3:防零约束(确保x[i,j]>0时工厂j已启用) M = max(demand.values()) def Const7(model,i,j): return model.x[i,j] <= M * model.Assign[j] model.consplant_binary=pyo.Constraint(model.select_combos,rule=Const7)
额外说明
- 原代码中
total_cost变量存在语法错误,已修正为total_costs_per_unit并调整字典格式; - 大M值需合理设置,建议取单个订单的最大需求量,避免数值过大导致求解不稳定。
内容的提问来源于stack exchange,提问作者Christos Logaras
相关产品推荐
相关产品推荐

