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

Pyomo生产计划优化报错:无法将标量组件'tsi'视为索引组件

解决Pyomo中"Cannot treat the scalar component 'tsi' as an indexed component"错误

问题根源

  1. 参数定义错误:用字典初始化tsi和trc时未指定索引集合,Pyomo默认将它们创建为标量参数,而非可索引的参数,因此无法通过model.tsi[m]的方式访问。
  2. 约束规则写法错误:原规则试图返回整个月份列表的等式,不符合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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 11:55:25