我想使用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)
问题的原始版本:
我想使用LinearConstraint对象 在scipy.optimize中,如此处的教程所述: "Defining linear constraints"
我试图做一个简单的例子,答案很明显:在平方<< = x <= 1,0 <= y <= 1上最小化x + y。下面是我的代码,该代码返回错误“'LinearConstraint'对象不可迭代”,但我看不到我如何尝试进行迭代。
编辑1:该示例故意过分简单。最终,我想在大量线性约束上最小化非线性函数。我知道我可以使用字典理解将约束矩阵转换成字典列表,但是我想知道是否可以将“ LinearConstraints”用作将矩阵转换为约束的现成方法。 >
编辑2:正如Johnny Drama所指出的,LinearConstraint用于特定方法。因此,在上面,我尝试使用他的建议来理解字典,以产生线性约束,但是仍然没有得到预期的答案。
代码的原始部分(现已不相关):
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)
答案 0 :(得分:3)
就像新手已经说过的那样,如果目标函数和约束是线性的,请使用linprog。对于您的约束是线性的而目标函数不是线性的情况,则必须使用以下最小化方法:
minimize(obj_fun, x0=xinit, bounds=bnds, constraints=cons)
其中obj_fun
是目标函数,xinit
是起始点,bnds
是变量边界的元组列表,而cons
是字典列表。 / p>
这是一个例子。假设您要
因为所有约束都是线性的,我们可以将其写为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。对于第一个约束,它将为
{"type": "ineq", "fun": lambda x: x[0] - 2* x[1] + 2}
由于其他方法的作用相同,因此可以定义
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}]
请注意,@
是矩阵乘法的运算符(仅自Python3.5起可用),我假设所有约束都是不等式约束。
通话
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])
编辑:要回答您的新问题:
# 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)
答案 1 :(得分:1)
错误在于您调用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. ]