[英]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.