簡體   English   中英

在 Pyomo 的目標函數中使用分段函數

[英]Using piecewise function in objective function in Pyomo

我試圖在我的目標函數中使用 Pyomo 的分段線性函數。 這個分段線性函數實際上是插入一個名為macc的值數組,它有 401 個值(macc[i], i 從 0 到 400)。 您可以在附圖中看到 macc 的值

在此處輸入圖片說明

我的目標函數正在尋找macc[i]遵守約束的值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(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.

關於如何解決這個問題的任何想法都會非常受歡迎。

如果需要,這里是完整的代碼。 對於這個例子,我用一個函數創建了數組 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)

@羅恩

正如 AirSquid 評論的那樣,您正在使用kernelenviron命名空間。 您應該避免這種混合,因為幾種方法可能不兼容。

無需使用__call__() ( f(model.x) ) 方法顯式評估分段函數,您可以使用輸入、輸出參數(在環境層中稱為xvaryvar )在定義的變量中輸出評估。

使用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)

在這種建模方法中,您沒有在每個方程(約束或目標)中評估model.piecewise(model.x)的問題,相反,您將只使用等效於評估的model.y

現在,我不知道你的問題,但我猜你的目標不是凸的,這可能是優化中的另一個問題。 您可以使用Gurobi來解決此類問題,但在這種情況下,由於model.y依賴於model.x並且model.x是有界的,因此會到達model.x上限以使目標盡可能低(因為您沒有在目標中聲明任何意義,我假設您想最小化)。 我認為你應該檢查你的目標是否代表你的想法。

你的目標函數是這樣的目標函數表示-

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM