You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 10:42:23