簡體   English   中英

scipy.optimize 中的線性約束

[英]LinearConstraint in scipy.optimize

我想使用 scipy.optimize 來最小化大量線性不等式上的函數(最終是非線性的)。 作為熱身,我試圖在 0<=x<=1、0<=y<=1 的方框上最小化 x+y。 按照下面 Johnny Drama 的建議,我目前正在使用 dict-comprehesion 來生成不等式字典,但沒有得到預期的答案(最小值 = 0,最小值在(0,0))。

新的代碼部分(當前相關):

import numpy as np
from scipy.optimize import minimize



#Create initial point.

x0=[.1,.1]

#Create function to be minimized

def obj(x):
    return x[0]+x[1]


#Create linear constraints  lbnd<= A*(x,y)^T<= upbnd

A=np.array([[1,0],[0,1]])

b1=np.array([0,0])

b2=np.array([1,1])

cons=[{"type": "ineq", "fun": lambda x: np.matmul(A[i, :],x) -b1[i]} for i in range(A.shape[0])]

cons2=[{"type": "ineq", "fun": lambda x: b2[i]-np.matmul(A[i, :], x) } for i in range(A.shape[0])]

cons.extend(cons2)

sol=minimize(obj,x0,constraints=cons)

print(sol)

問題的原始版本:

我想在 scipy.optimize 中使用 LinearConstraint 對象,如教程中所述: “定義線性約束”

我試着做一個更簡單的例子,答案應該是顯而易見的:在正方形 0<=x<=1, 0<=y<=1 上最小化 x+y。 下面是我的代碼,它返回錯誤“'LinearConstraint' object is not iterable”,但我看不出我是如何嘗試迭代的。

編輯 1:該示例故意過於簡單。 最終,我想在大量線性約束下最小化非線性函數。 我知道我可以使用字典理解將我的約束矩陣轉換為字典列表,但我想知道“LinearConstraints”是否可以用作將矩陣轉換為約束的現成方法。

編輯 2:正如 Johnny Drama 所指出的,LinearConstraint 是針對特定方法的。 因此,在上面我嘗試使用他的建議來代替 dict-comprehension 來產生線性約束,但我仍然沒有得到預期的答案。

原始代碼部分(現在無關緊要):

from scipy.optimize import minimize
from scipy.optimize import LinearConstraint


#Create initial point.

x0=[.1,.1]

#Create function to be minimized

def obj(x):
    return x[0]+x[1]


#Create linear constraints  lbnd<= A* 
#(x,y)^T<= upbnd

A=[[1,0],[0,1]]

lbnd=[0,0]

upbnd=[0,0]

lin_cons=LinearConstraint(A,lbnd,upbnd)

sol=minimize(obj,x0,constraints=lin_cons)

print(sol)

正如新手已經說過的,如果你想解決 LP(線性程序),請使用scipy.optimize.linprog ,即你的目標函數你的約束是線性的。 如果目標或約束之一不是線性的,我們將面臨 NLP(非線性優化問題),可以通過scipy.optimize.minimize解決:

minimize(obj_fun, x0=xinit, bounds=bnds, constraints=cons)

其中obj_fun是您的目標函數, xinit是一個初始點, bnds是變量邊界的元組列表, cons是約束指令列表。


這是一個例子。 假設我們要解決以下 NLP:

在此處輸入圖像描述

由於所有約束都是線性的,我們可以用仿射線性函數A*xb來表示它們,這樣我們就有了不等式A*x >= b 這里A是一個 3x2 矩陣, b是 3x1 右側向量:

import numpy as np
from scipy.optimize import minimize

obj_fun = lambda x: (x[0] - 1)**2 + (x[1] - 2.5)**2
A = np.array([[1, -2], [-1, -2], [-1, 2]])
b = np.array([-2, -6, -2])
bnds = [(0, None) for i in range(A.shape[1])]  # x_1 >= 0, x_2 >= 0
xinit = [0, 0] 

現在剩下要做的唯一一件事就是定義約束,每個約束都必須是形式的字典

{"type": "ineq", "fun": constr_fun}

其中constr_fun是一個可調用函數,滿足constr_fun >= 0 因此,我們可以定義每個約束

cons = [{'type': 'ineq', 'fun': lambda x:  x[0] - 2 * x[1] + 2},
        {'type': 'ineq', 'fun': lambda x: -x[0] - 2 * x[1] + 6},
        {'type': 'ineq', 'fun': lambda x: -x[0] + 2 * x[1] + 2}]

我們就完成了。 然而,事實上,對於許多約束來說,這可能是相當麻煩的。 相反,我們可以通過以下方式直接傳遞所有約束:

cons = [{"type": "ineq", "fun": lambda x: A @ x - b}]

其中@表示矩陣乘法運算符 把所有放在一起

res = minimize(obj_fun, x0=xinit, bounds=bnds, constraints=cons)
print(res)

產量

     fun: 0.799999999999998
     jac: array([ 0.79999999, -1.59999999])
 message: 'Optimization terminated successfully.'
    nfev: 16
     nit: 4
    njev: 4
  status: 0
 success: True
       x: array([1.39999999, 1.69999999])

同樣,您可以使用LinearConstraint對象:

from scipy.optimize import LinearConstraint

# lb <= A <= ub. In our case: lb = b, ub = inf
lincon = LinearConstraint(A, b, np.inf*np.ones(3))

# rest as above
res = minimize(obj_fun, x0=xinit, bounds=bnds, constraints=(lincon,))

編輯:回答你的新問題:

# b1    <= A * x   <==>   -b1 >= -A*x        <==>   A*x - b1 >= 0
# A * x <= b2      <==>    A*x - b2 <= 0     <==>  -Ax + b2 >= 0
cons = [{"type": "ineq", "fun": lambda x: A @ x - b1}, {"type": "ineq", "fun": lambda x: -A @ x + b2}]
sol=minimize(obj,x0,constraints=cons)
print(sol)

錯誤在於您調用minimize函數的方式

sol= minimize(obj, x0, constraints=lin_cons)

實際上,約束需要字典或字典列表,請參閱http://scipy.optimize.minimize

對於您的特定 LP,我會這樣寫:

from scipy.optimize import linprog
import numpy as np

c = np.array([1, 1])

res = linprog(c, bounds=(0, 1))

print('Optimal value: {}'.format( res.fun))
print('Values: {}'.format(res.x))

哪個輸出

Optimal value: -0.0
Values: [ 0.  0.]

因為沒有約束。

假設您要添加約束x + y >= 0.5 (相當於-x - y <= -0.5 )。 然后你的 Lp 變成:

c = np.array([1, 1])

A_ub = np.array([[-1,-1]])

b_ub = np.array([-0.5])

res = linprog(c, A_ub=A_ub, b_ub=b_ub, bounds=(0, 1))

print('Optimal value: {}'.format( res.fun))
print('Values: {}'.format(res.x))

現在輸出:

Optimal value: 0.5
Values: [ 0.5  0. ]

@喬尼:

b1 <= A * x <==> -b1 >= -A x <==> A x - b1 >= 0

A * x <= b2 <==> A*x - b2 <= 0 <==> -Ax + b2 >= 0

cons = [{“type”:“ineq”,“fun”:lambda x:A @ x - b1},{“type”:“ineq”,“fun”:lambda x:-A @ x + b2}]

溶膠=最小化(obj,x0,約束=缺點)打印(溶膠)

這是一個非常有趣的解決方案,對我來說效果很好。 我正在嘗試做同樣的事情,但同時具有平等和不平等約束:

所以我有: Aeq @ x - b =0 並且它工作正常但是當我添加 A_ineq @ x - Lb 和 Ub - A_ineq @ x 它似乎不起作用因為 Aeq 和 AIneq 不是相同的尺寸:

def DefineLinearConstraint(Aeq, b, Aineq, Lb, Ub): 約束 = [{"type": "eq", "fun": lambda x: Aeq @ x - b, {"type": "ineq", "fun" ": lambda x: Aineq @ x - Lb}, {"type": "ineq", "fun": lambda x: -Aineq @ x + Ub}]

我有以下變量: Aeq = array([1, 1, 1, 1, 1], dtype=int64) x0 = array([[0.2], [0.2], [0.2],[0.2], [0.2] ], dtype=object) 和 x 與 x0 相同的維度, b = array([1], dtype=object)

對於不等式約束:Aineq = array([[1, 1, 1, 0, 0], [0, 0, 0, 1, 1]], dtype=int64)

Lb = array([[0], [0]], dtype=object) and Ub = array([[1], [1]], dtype=object)

我的想法是添加組約束,在我的示例中,我有 2 個我希望能夠修改的組約束。

暫無
暫無

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

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