Pyomo生产计划优化报错:无法将标量组件'tsi'视为索引组件
解决Pyomo中"Cannot treat the scalar component 'tsi' as an indexed component"错误
问题根源
- 参数定义错误:用字典初始化
tsi和trc时未指定索引集合,Pyomo默认将它们创建为标量参数,而非可索引的参数,因此无法通过model.tsi[m]的方式访问。 - 约束规则写法错误:原规则试图返回整个月份列表的等式,不符合Pyomo约束逻辑——约束规则需针对单个索引元素(单个月份)生成独立约束。
修正方案
1. 正确定义索引参数
先创建月份集合setm,再将tsi和trc绑定为该集合的索引参数。
2. 修正约束规则逻辑
每个约束规则仅处理单个月份m,直接返回该月份对应的等式,摒弃列表推导式的批量写法。
修正后的完整代码
import pyomo.environ as pyo from pyomo.opt import SolverFactory def run(): model = pyo.ConcreteModel() Dict1 = {1:28800,2:26200,3:20900,4:12660,5:25770,6:12350,7:28200,8:26200,9:30000,10:7400,11:24000,12:22200} Dict2 = {1:5000,2:5700,3:4000,4:1540,5:9000,6:1800,7:7250,8:4000,9:8000,10:3000,11:5000,12:8100} # 定义数值参数,避免与索引变量m混淆 model.m_val = pyo.Param(initialize=12) model.k_val = pyo.Param(initialize=2) model.i_val = pyo.Param(initialize=3) model.j_val = pyo.Param(initialize=3) model.l_val = pyo.Param(initialize=2) # 先创建集合,再基于集合定义索引参数 model.setm = pyo.RangeSet(1, model.m_val) model.setk = pyo.RangeSet(1, model.k_val) model.seti = pyo.RangeSet(1, model.i_val) model.setj = pyo.RangeSet(1, model.j_val) model.setl = pyo.RangeSet(1, model.l_val) # 定义带索引的需求参数 model.tsi = pyo.Param(model.setm, initialize=Dict1) model.trc = pyo.Param(model.setm, initialize=Dict2) # 补充变量定义(原代码缺失,需确保所有变量已定义) model.g = pyo.Var(model.setk, model.setm, domain=pyo.NonNegativeReals) model.G = pyo.Var(model.setk, model.setm, domain=pyo.Binary) model.z = pyo.Var(model.setk, model.setj, model.setm, domain=pyo.NonNegativeReals) model.p = pyo.Var(model.setk, model.setj, model.setm, domain=pyo.NonNegativeReals) model.dr = pyo.Var(model.setk, model.setm, domain=pyo.NonNegativeReals) # 修正后的约束规则 def sixteenthRule(model, m): return model.g[1, m] == model.trc[m] * model.G[1, m] + model.tsi[m] def seventeenthRule(model, m): return model.g[2, m] == model.trc[m] * (1 - model.G[1, m]) def twentyeightthRule(model, m): # 处理第一个月的初始库存边界 if m == 1: return model.z[1, 1, m] == model.p[1, 1, m] - model.tsi[m] else: return model.z[1, 1, m] == model.z[1, 1, m-1] + model.p[1, 1, m] - model.tsi[m] def thirtythRule(model, m): # 处理第一个月的初始库存边界 if m == 1: return model.z[1, 2, m] == model.p[2, 2, m] + model.dr[2, m] - model.G[1, m] * model.trc[m] + model.p[1, 2, m] else: return model.z[1, 2, m] == model.z[1, 2, m-1] + model.p[2, 2, m] + model.dr[2, m] - model.G[1, m] * model.trc[m] + model.p[1, 2, m] # 将约束添加到模型 model.sixteenth_con = pyo.Constraint(model.setm, rule=sixteenthRule) model.seventeenth_con = pyo.Constraint(model.setm, rule=seventeenthRule) model.twentyeightth_con = pyo.Constraint(model.setm, rule=twentyeightthRule) model.thirtyth_con = pyo.Constraint(model.setm, rule=thirtythRule) # 后续可添加目标函数与求解逻辑 # model.obj = pyo.Objective(expr=..., sense=pyo.minimize) # solver = SolverFactory('glpk') # solver.solve(model) if __name__ == "__main__": run()
关键修改说明
- 重命名数值参数
model.m为model.m_val,避免与索引变量m冲突 - 先创建
setm集合,再将tsi和trc定义为该集合的索引参数,支持model.tsi[m]的正常访问 - 约束规则改为针对单个月份生成约束,同时处理了第一个月的初始库存边界(避免
m-1索引越界) - 补充了变量定义框架,确保代码运行时所有变量都已正确声明
内容的提问来源于stack exchange,提问作者christina
相关产品推荐
相关产品推荐

