简体   繁体   English

在 Pyomo 的目标函数中使用分段函数

[英]Using piecewise function in objective function in Pyomo

I am trying to use a piecewise linear function from Pyomo in my objective function.我试图在我的目标函数中使用 Pyomo 的分段线性函数。 This piecewise linear function is actually interpolating an array of values called macc , having 401 values (macc[i], i from 0 to 400).这个分段线性函数实际上是插入一个名为macc的值数组,它有 401 个值(macc[i], i 从 0 到 400)。 You can see the values of macc in the picture attached您可以在附图中看到 macc 的值

在此处输入图片说明

My objective function is looking for the value i for which macc[i] respect the constraints.我的目标函数正在寻找macc[i]遵守约束的值i To do that I interpolate the array macc to have a continuous function f.为此,我插入数组 macc 以获得连续函数 f。 See below:见下文:

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)

But when I try to call this function f in my objective function above, I get the message below for the expression ab = f(mx) in the objective function:但是,当我尝试在上面的目标函数中调用此函数 f 时,我收到以下关于目标函数中表达式ab = f(mx)的消息:

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.

Any idea on how to solve that would be very welcome.关于如何解决这个问题的任何想法都会非常受欢迎。

Here is the complete code if needed.如果需要,这里是完整的代码。 For this example I created the array macc with a function, but in reality it does not come from a function but from internal data.对于这个例子,我用一个函数创建了数组 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)

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 @罗恩

As AirSquid commented, you're using the kernel and environ namespace.正如 AirSquid 评论的那样,您正在使用kernelenviron命名空间。 You should avoid this mixing, since several approach may not be compatible.您应该避免这种混合,因为几种方法可能不兼容。

Instead of explicit evaluating the piecewised funtion using the __call__() ( f(model.x) ) method you can use the input, output args (in environ layer are called xvar , yvar ) to output the evaluation in a defined variable.无需使用__call__() ( f(model.x) ) 方法显式评估分段函数,您可以使用输入、输出参数(在环境层中称为xvaryvar )在定义的变量中输出评估。

Using the environ layer, piecewise function are available in pyo.Piecewise使用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,4)
macc = 2000*logistic(c,L=0.5,x_0 = 60,k=0.02)

s0 = 800
b0 = 1000
tnac0 = 100

cp0 = 10
ab0 = 100
#Start modeling
model = pyo.ConcreteModel()

#Declare variable
model.x = pyo.Var(domain=pyo.NonNegativeReals, bounds=(5,395), initialize = cp0)
model.y = pyo.Var() #The output of piecewise. Equivalent to model.y=piecewise(model.x)
model.piecewise = pyo.Piecewise(
                                model.y, 
                                model.x, 
                                pw_pts=list(c), 
                                f_rule=list(macc), 
                                pw_constr_type='EQ'
                                )
#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
model.Obj = pyo.Objective(expr= (model.b - model.y)*model.x, sense=pyo.minimize)

#Constraints
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)

In this modeling approach you don't have the problem of evaluate model.piecewise(model.x) in each equation (constraint or objective), instead you will just use model.y which is equivalent to evaluate.在这种建模方法中,您没有在每个方程(约束或目标)中评估model.piecewise(model.x)的问题,相反,您将只使用等效于评估的model.y

Now, I don't know your problem, but that I guess your objective is not convex, which may be a further problem in the optimization.现在,我不知道你的问题,但我猜你的目标不是凸的,这可能是优化中的另一个问题。 you can use Gurobi to solve such problems, but in this case, as model.y depends upon model.x and model.x is bounded, is going to the model.x upper bound in order to make objective as low as possible (since you don't declare any sense in the objective, I assume that you want to minimize).您可以使用Gurobi来解决此类问题,但在这种情况下,由于model.y依赖于model.x并且model.x是有界的,因此会到达model.x上限以使目标尽可能低(因为您没有在目标中声明任何意义,我假设您想最小化)。 I think you should check your objective if it represents what you think.我认为你应该检查你的目标是否代表你的想法。

Your objective function is doint something like this你的目标函数是这样的目标函数表示-

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM