pyomo中如何仅使用Set的部分元素为Variable做索引避免KeyError
问题原因
Pyomo的pe.Set是专用的有序集合对象,不支持Python原生的切片语法,所以直接使用model.times[0:-2]会触发类型错误。同时你的切片范围也存在偏差:model.times取值为0~95共96个元素,只需要去掉最后1个元素即可保证t+1不越界,不需要去掉2个。
可行解决方案
方案1:临时转换为Python列表切片
适合只需要单次使用该时间范围的场景,直接在求和时将Set转为原生列表再切片即可:
def example_rule(model): # 先将Set转为Python原生列表,再切片去掉最后1个元素 return sum(sum(model.SOC[t+1, b] - model.SOC[t, b] for b in model.buses) for t in list(model.times)[:-1])
方案2:预先创建相邻时间步子集
适合多处需要用到该时间范围(比如写充放电约束、SOC上下限约束等)的场景,是Pyomo建模的标准规范写法:
首先在模型定义阶段提前声明不含最后一个时间步的子集:
# 定义不含最后一个时间步的子集,专门用于SOC递推类逻辑 model.t_prev = pe.Set(initialize=[t for t in model.times if t < max(model.times)])
之后在目标函数或约束规则中直接遍历该子集即可:
def example_rule(model): return sum(sum(model.SOC[t+1, b] - model.SOC[t, b] for b in model.buses) for t in model.t_prev)
完整可运行修改后代码
import pyomo.environ as pe solver = pe.SolverFactory('glpk') model = pe.ConcreteModel('Test') model.times = pe.Set(initialize=list(range(96))) # 新增相邻时间步子集 model.t_prev = pe.Set(initialize=[t for t in model.times if t < max(model.times)]) model.buses = pe.Set(initialize=list(range(5))) model.SOC = pe.Var(model.times*model.buses, domain=pe.PositiveReals) def example_rule(model): return sum(sum(model.SOC[t+1, b] - model.SOC[t, b] for b in model.buses) for t in model.t_prev) model.obj = pe.Objective(rule=example_rule, sense=pe.maximize) model.pprint()
内容的提问来源于stack exchange,提问作者Andre
相关产品推荐
相关产品推荐

