python - 在 Pyomo 的目标函数中使用分段函数
问题描述
我试图在我的目标函数中使用 Pyomo 的分段线性函数。这个分段线性函数实际上是对一个名为 的值数组进行插值macc
,它有 401 个值(macc[i], i 从 0 到 400)。您可以在附图中看到 macc 的值
我的目标函数是寻找尊重约束的i
值macc[i]
。为此,我对数组 macc 进行插值,使其具有连续函数 f。见下文:
c = np.arange(401)
f = pyopiecewise.piecewise(c,macc,validate=False)
model = pyo.ConcreteModel()
#Declare variable
model.x = pyo.Var(domain=pyo.NonNegativeReals, bounds=(5,395), initialize = cp0)
#Declare parameters
model.s = pyo.Param(domain=pyo.NonNegativeReals,initialize=s0)
model.b = pyo.Param(domain=pyo.NonNegativeReals,initialize=b0)
model.tnac = pyo.Param(domain=pyo.NonNegativeReals,initialize=tnac0)
#Objective function
def objective_(m):
ab = f(m.x)
e = m.b - ab
return (e * m.x)
#Constraints
def constraint1(m):
ab = f(m.x)
e = m.b - ab
return e <= (m.tnac + m.s)
但是,当我尝试在上面的目标函数中调用此函数 f 时,我会收到以下关于ab = f(m.x)
目标函数中表达式的消息:
ERROR: Rule failed when generating expression for Objective Obj with index
None: PyomoException: Cannot convert non-constant expression to bool. This
error is usually caused by using an expression in a boolean context such
as an if statement. For example,
m.x = Var() if m.x <= 0:
...
would cause this exception.
ERROR: Constructing component 'Obj' from data=None failed: PyomoException:
Cannot convert non-constant expression to bool. This error is usually
caused by using an expression in a boolean context such as an if
statement. For example,
m.x = Var() if m.x <= 0:
...
would cause this exception.
任何关于如何解决这个问题的想法都将非常受欢迎。
如果需要,这是完整的代码。对于这个示例,我使用函数创建了数组 macc,但实际上它不是来自函数,而是来自内部数据。
import numpy as np
import pyomo.environ as pyo
import pyomo.core.kernel.piecewise_library.transforms as pyopiecewise
#Create macc
# logistic sigmoid function
def logistic(x, L=1, x_0=0, k=1):
return L / (1 + np.exp(-k * (x - x_0)))
c = np.arange(401)
macc = 2000*logistic(c,L=0.5,x_0 = 60,k=0.02)
macc = macc -macc[0]
f = pyopiecewise.piecewise(c,macc,validate=False)
s0 = 800
b0 = 1000
tnac0 = 100
cp0 = 10
ab0 = 100
model = pyo.ConcreteModel()
#Declare variable
model.x = pyo.Var(domain=pyo.NonNegativeReals, bounds=(5,395), initialize = cp0)
#Declare parameters
model.s = pyo.Param(domain=pyo.NonNegativeReals,initialize=s0)
model.b = pyo.Param(domain=pyo.NonNegativeReals,initialize=b0)
model.tnac = pyo.Param(domain=pyo.NonNegativeReals,initialize=tnac0)
#Objective function
def objective_(m):
ab = f(m.x)
e = m.b - ab
return (e * m.x)
model.Obj = pyo.Objective(rule=objective_)
#Constraints
def constraint1(m):
ab = f(m.x)
e = m.b - ab
return e <= (m.tnac + m.s)
def constraint2(m):
ab = f(m.x)
e = m.b - ab
return e >= 1
def constraint3(m):
ab = f(m.x)
return ab >= 0
model.con1 = pyo.Constraint(rule = constraint1)
model.con2 = pyo.Constraint(rule = constraint2)
model.con3 = pyo.Constraint(rule = constraint3)
解决方案
@RonB
正如 AirSquid 评论的那样,您正在使用kernel
andenviron
命名空间。您应该避免这种混合,因为几种方法可能不兼容。
代替使用__call__()
( f(model.x)
) 方法显式评估分段函数,您可以使用输入、输出参数(在环境层中称为xvar
, yvar
)在定义的变量中输出评估。
使用 environ 层,pyo.Piecewise中提供了分段函数
import numpy as np
import pyomo.environ as pyo
#Create macc
# logistic sigmoid function
def logistic(x, L=1, x_0=0, k=1):
return L / (1 + np.exp(-k * (x - x_0)))
c = np.linspace(0,400,400)
macc = 2000*logistic(c,L=0.5,x_0 = 60,k=0.02)
macc = macc -macc[0]
s0 = 800
b0 = 1000
tnac0 = 100
cp0 = 10
ab0 = 100
model = pyo.ConcreteModel()
#Declare variable
model.x = pyo.Var(domain=pyo.NonNegativeReals, bounds=(5,395), initialize = cp0)
model.y = pyo.Var()
model.piecewise = pyo.Piecewise(model.y, model.x, pw_pts=list(c), f_rule=list(macc), pw_constr_type='EQ', pw_repn='DCC')
#Declare parameters
model.s = pyo.Param(domain=pyo.NonNegativeReals,initialize=s0)
model.b = pyo.Param(domain=pyo.NonNegativeReals,initialize=b0)
model.tnac = pyo.Param(domain=pyo.NonNegativeReals,initialize=tnac0)
model.Obj = pyo.Objective(expr= model.b*model.x - model.y*model.x, sense=pyo.minimize)
model.con1 = pyo.Constraint(expr=model.b - model.y <= model.tnac + model.s)
model.con2 = pyo.Constraint(expr=model.b - model.y >= 1)
model.con3 = pyo.Constraint(expr= model.y >= 0)
solver = pyo.SolverFactory('ipopt')
solver.solve(model, tee=True)
在这种建模方法中,您没有model.piecewise(model.x)
在每个方程(约束或目标)中进行评估的问题,相反,您只需使用model.y
相当于评估的方法。
现在,我不知道你的问题,但我猜你的目标不是凸的,这可能是优化中的另一个问题。你可以用它Gurobi
来解决这样的问题,但在这种情况下,model.y
取决于model.x
和model.x
有界,model.x
为了使目标尽可能低(因为你没有在目标中声明任何意义,我假设你想最小化)。我认为你应该检查你的目标是否代表你的想法。
推荐阅读
- machine-learning - 从中文文档中提取数据
- vespa - 'vespa.ai' 中不区分大小写的匹配
- opencart - 如何将 Opencart 从根目录移动到子文件夹
- google-bigquery - 如何使用 BigQueryIO.read 使用 SerializableFunction() 而不是 BigQueryIO.readTableRows()
- javascript - require.context 不会随着图片上传而更新
- angular - 错误:this.scrollableDiv.nativeElement 未定义
- r - Plotly:用动画图表处理缺失值
- javascript - 重新启动时防止视频重新加载
- windows - Jenkins 构建后如何在 Windows 上启动应用程序
- c# - CREATE FILE 在尝试打开或创建物理文件时遇到操作系统错误 5(访问被拒绝。)