如何使用 pyomo 在 objective 函数的求和范围内包含一个变量?

How to include a variable in the summation bound of a objective function with pyomo?

我正在使用 pyomo 寻找解决能源优化问题的方法。我正在尝试找到一天中的最佳时间段以将智能洗碗机的启动时间转移到,以便将电费降至最低。

我正在使用来自 paper 的示例,但不幸的是我还不能嵌入图片,所以这里是描述问题的图片的 links:

我知道如何使用 pyomo 解决一个简单的多周期优化问题。如果 objective 函数中总和的边界是固定的,我可以写“sum(... for t in m.T)”。请参阅以下代码示例以更好地理解我的意思:

from pyomo.environ import *

model = ConcreteModel()
model.T = RangeSet(5)
...

model.y = Var(model.T, domain=Binary)    
model.i_pos = Var(model.T, domain=NonNegativeReals)
model.i_neg = Var(model.T, domain=NegativeReals)
...

c = 30  # setup cost: fixe Kosten pro Zeitschritt wenn in diesem Zeitschritt produziert werden muss
h_pos = 0.7  # cost per unit of holding inventory
h_neg = 1.2  # shortage cost per unit
P = 5.0  # maximum production amount per time step
...

def obj_rule(m):
   return sum(c*m.y[t] + h_pos*m.i_pos[t] + h_neg*m.i_neg[t] for t in m.T)
model.obj = Objective(rule=obj_rule, sense=minimize)

现在我对提到的能量优化问题的问题是,我不知道如何在 pyomo 的总和范围内包含一个变量。案例是变量s_n,i(见link:问题描述)描述了洗碗机的启动时间段,但也包含在我的objective函数的总和中,它最小化花费。因此,我需要以某种方式将我的变量 s_n,i 放入我的 objective 函数的“for t in m.T”部分。

我对论文中的问题做了一点修改:

这是我当前的代码:

from pyomo.environ import *

model = ConcreteModel()
# 7 time steps
model.T = RangeSet(7)


a = 1  # earliest starting time slot for the dishwasher
b = 7  # lastest ending time slot for the dishwasher
d = 2  # duration dishwasher in h
p = 1  # power dishwasher in kW

# electricity cost per time step in €/kWh
cost = {1: 0.4, 2: 0.3, 3: 0.3, 4: 0.15, 5: 0.25, 6: 0.30, 7: 0.35}

# definition of the variable s_n,i
model.start = Var(bounds=(a, b-d), domain=NonNegativeReals)

def obj_rule(m):
    return sum(cost[t]*p for t in m.T)
model.obj = Objective(rule=obj_rule, sense=minimize)

solver = SolverFactory('glpk')
solver.solve(model)

感谢您的帮助!

欢迎访问本网站。您的问题更多是数学编程而不是编码问题,但让我们试一试...

我希望你对整数规划有一定的了解,因为这是你需要解决这个问题的地方,以修复你被挂断的部分。

考虑更改您的 start 变量。 (为方便起见,我们将其重命名为 Y。)让我们决定 Y_j 是一个二进制变量,表示在 j 期间启动机器的决定,其中 j 是一个允许开始的时间段 T 的子集。现在我们可以在您的 objective 函数中使用一些东西....

然后在objective中,我们会想看求和元素,看看Y_j在当前或前2个时间段是否为1(选中)(假设机器运行 3 个时间步)。

或者,您可以引入另一个变量来指示机器是否在任何特定时期 运行 并设置约束以基于 Y_j.

强制该变量

根据您设置问题的方式,您需要对 Y_j 进行一两个约束,当然,尤其是 sum(Y_j) = 1

如果您卡住了,请回复。

编辑:下面的实现

有几种方法可以解决这个问题。下面的一个使用 2 个变量作为开始时间段,一个变量用于“运行”。我认为您可以使用更复杂的 objective 函数稍微改进一下,只使用“start”变量,但这与您的评论一致。

# pick the cheapest 2-consecutive periods to run an appliance

import pyomo.environ as pyo

# Data
costs = {   1:10,
            2:5,
            3:7,
            4:15}
num_periods = 4
run_time = 2  # the number of periods the machine runs

m = pyo.ConcreteModel('appliance runner')

# SETS
m.T       = pyo.RangeSet(num_periods)
m.T_start = pyo.RangeSet(num_periods - (run_time - 1))  # legal starts {1,2,3}

# VARS
m.Y = pyo.Var(m.T_start, domain=pyo.Binary)  # the period to START
m.X = pyo.Var(m.T, domain=pyo.Binary)        # machine running



# CONSTRAINTS
# must start at least once
m.C1 = pyo.Constraint(expr=sum(m.Y[t] for t in m.T_start) >=1 )

# periods after the start, the machine must be on for run_time
# (this is the tricky one...  couple ways to do this...)

def running(self, t):
    return m.X[t] >= sum(m.Y[t2] for t2 in 
                        range(t, t-run_time, -1) 
                        if t2 in m.T_start)
m.C2 = pyo.Constraint(m.T, rule=running)
# m.pprint()  <-- use this to see what was created in this constraint

# OBJ
m.OBJ = pyo.Objective(expr=sum(m.X[t]*costs[t] for t in m.T))

solver = pyo.SolverFactory('glpk')
results = solver.solve(m)
print(results)
m.display()