Pyomo报错:无法对非集合ConcreteModel组件应用集合运算符
Pyomo优化模型TypeError问题解决
问题重现
以下是报错的Pyomo模型代码:
# model definition model = ConcreteModel() # Sets and indices model.O = RangeSet(len(data)) # Set of representative operating conditions model.D = RangeSet(len(data)) # Demand profile for the operating conditions model.G = RangeSet(1) # set of existing generators model.C = RangeSet(1) # set of candidate generators # Parameters model.Cg= Param(initialize=35, within=NonNegativeReals, mutable=True) # Opex of existing generators model.Cc= Param(initialize=25, within=NonNegativeReals, mutable=True) # Opex of candidate generators model.Ic= Param(initialize=70000, within=NonNegativeReals, mutable=True) # Annualized investment cost # Decision Variables model.pg = Var(model.O, model.G, bounds=(0, 400), initialize=0, within=NonNegativeReals) model.pc = Var(model.O, model.C, bounds=(0, 500), initialize=0, within=NonNegativeReals) model.pc_max = Var(model.C, bounds=(0, 500), initialize=0, within=NonNegativeIntegers) # Objective function def objective_rule(model, O): return sum(data.loc[O-1, 'w']*(sum(model.Cg*model.pg[O,G] for G in model.G))+\ data.loc[O-1, 'w']*(sum(model.Cc*model.pc[O,C] for C in model.C)) for O in model.O)+\ sum(model.Ic*model.pc_max[C] for C in model.C) model.objective = Objective(model, rule=objective_rule, sense=minimize) # Constraints # 1. sign restrictions already provided for in the definition of decision variables def con1_limit_candidate_units(model, O, C): return model.pc[O,C] <= model.pc_max[C] model.con1 = Constraint(model.O, model.C, rule=con1_limit_candidate_units) def con2_power_balance(model, O, G): return sum(model.pg[O, G] for G in model.G) + sum(model.pc[O, C] for C in model.C) == data.loc[O-1, 'd'] model.con2 = Constraint(model.O, model.G, rule = con2_power_balance) opt = SolverFactory('cplex') instance = model.create_instance() results = opt.solve(instance) # solves and updates instance print('Objective value=',value(instance.objective))
运行后抛出错误:
TypeError Traceback (most recent call last) ~\AppData\Local\Temp/ipykernel_5960/507444092.py in <module> 36 sum(model.Ic*model.pc_max[C] for C in model.C) 37 ---> 38 model.objective = Objective(model, rule=objective_rule, sense=minimize) 39 #Constraints 40 #1. sign restrictions already provided for in the definition of decision variables ~\anaconda3\lib\site-packages\pyomo\core\base\objective.py in __init__(self, *args, **kwargs) 279 280 kwargs.setdefault('ctype', Objective) ---> 281 ActiveIndexedComponent.__init__(self, *args, **kwargs) 282 283 self.rule = Initializer(_init) ~\anaconda3\lib\site-packages\pyomo\core\base\indexed_component.py in __init__(self, *args, **kwds) 1046 1047 def __init__(self, *args, **kwds): -> 1048 IndexedComponent.__init__(self, *args, **kwds) 1049 # Replicate the ActiveComponent.__init__() here. We don't want 1050 # to use super, because that will run afoul of certain ~\anaconda3\lib\site-packages\pyomo\core\base\indexed_component.py in __init__(self, *args, **kwds) 289 # 290 self._implicit_subsets = None -> 291 self._index = process_setarg(args[0]) 292 else: 293 # ~\anaconda3\lib\site-packages\pyomo\core\base\set.py in process_setarg(arg) 118 % (arg.ctype.__name__, arg.name,)) 119 if isinstance(arg, Component): -> 120 raise TypeError("Cannot apply a Set operator to a non-Set " 121 "%s component (%s)" 122 % (arg.__class__.__name__, arg.name,)) TypeError: Cannot apply a Set operator to a non-Set ConcreteModel component (unknown)
报错原因
- Objective构造参数错误:原代码中
Objective(model, rule=...)把model作为第一个参数传递,Pyomo会将这个参数解析为索引集合,而model是ConcreteModel对象,不是集合,因此触发类型错误。 - 目标函数Rule定义错误:
objective_rule(model, O)额外声明了O参数,Pyomo会认为这个目标函数是按O索引的多目标函数,但实际我们需要的是全局单目标函数,多余的参数导致Pyomo错误地尝试将目标函数索引化。
解决方法
步骤1:修正目标函数Rule
移除Rule中多余的O参数,因为目标函数是对所有操作条件求和的全局表达式:
def objective_rule(model): return sum(data.loc[O-1, 'w']*(sum(model.Cg*model.pg[O,G] for G in model.G))+\ data.loc[O-1, 'w']*(sum(model.Cc*model.pc[O,C] for C in model.C)) for O in model.O)+\ sum(model.Ic*model.pc_max[C] for C in model.C)
步骤2:修正Objective创建方式
不需要将model作为第一个参数传递,正确写法如下:
model.objective = Objective(rule=objective_rule, sense=minimize)
步骤3:(可选)约束优化
原约束con2_power_balance的索引包含G,但约束逻辑是对每个O的功率平衡,不需要按G索引,修正约束定义:
def con2_power_balance(model, O): return sum(model.pg[O, G] for G in model.G) + sum(model.pc[O, C] for C in model.C) == data.loc[O-1, 'd'] model.con2 = Constraint(model.O, rule = con2_power_balance)
修正后完整代码
# model definition model = ConcreteModel() # Sets and indices model.O = RangeSet(len(data)) # Set of representative operating conditions model.D = RangeSet(len(data)) # Demand profile for the operating conditions model.G = RangeSet(1) # set of existing generators model.C = RangeSet(1) # set of candidate generators # Parameters model.Cg= Param(initialize=35, within=NonNegativeReals, mutable=True) # Opex of existing generators model.Cc= Param(initialize=25, within=NonNegativeReals, mutable=True) # Opex of candidate generators model.Ic= Param(initialize=70000, within=NonNegativeReals, mutable=True) # Annualized investment cost # Decision Variables model.pg = Var(model.O, model.G, bounds=(0, 400), initialize=0, within=NonNegativeReals) model.pc = Var(model.O, model.C, bounds=(0, 500), initialize=0, within=NonNegativeReals) model.pc_max = Var(model.C, bounds=(0, 500), initialize=0, within=NonNegativeIntegers) # Objective function def objective_rule(model): return sum(data.loc[O-1, 'w']*(sum(model.Cg*model.pg[O,G] for G in model.G))+\ data.loc[O-1, 'w']*(sum(model.Cc*model.pc[O,C] for C in model.C)) for O in model.O)+\ sum(model.Ic*model.pc_max[C] for C in model.C) model.objective = Objective(rule=objective_rule, sense=minimize) # Constraints # 1. sign restrictions already provided for in the definition of decision variables def con1_limit_candidate_units(model, O, C): return model.pc[O,C] <= model.pc_max[C] model.con1 = Constraint(model.O, model.C, rule=con1_limit_candidate_units) def con2_power_balance(model, O): return sum(model.pg[O, G] for G in model.G) + sum(model.pc[O, C] for C in model.C) == data.loc[O-1, 'd'] model.con2 = Constraint(model.O, rule = con2_power_balance) opt = SolverFactory('cplex') instance = model.create_instance() results = opt.solve(instance) # solves and updates instance print('Objective value=',value(instance.objective))
内容的提问来源于stack exchange,提问作者Mr. EAo
相关产品推荐
相关产品推荐

