scipy.optimize

时间:2018-08-24 09:55:13

标签: python scipy

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

2 个答案:

答案 0 :(得分:3)

就像新手已经说过的那样,如果目标函数和约束是线性的,请使用linprog。对于您的约束是线性的而目标函数不是线性的情况,则必须使用以下最小化方法:

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

其中obj_fun是目标函数,xinit是起始点,bnds是变量边界的元组列表,而cons是字典列表。 / p>


这是一个例子。假设您要

enter image description here

因为所有约束都是线性的,我们可以将其写为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. ]