如何对多个变量正确使用 minimize from scipy?

How to use minimize from scipy correctly with multible variables?

我有五个变量要服从 scipy.optimize.minimize 以便根据 ABC 找到我正在寻求的解决方案、DE。首先,我从 scipy 导入 minimize 并定义了初始猜测(基于实验室实验,因此它们应该是有效的)。

from scipy.optimize import minimize

A0 = 1.90
B0 = 6.40
C0 = 11.7
D0 = 3.70
E0 = 2.50

ABCDE0 = [A0, B0, C0, D0, E0]

其次,我定义了构成 objective 函数的各个函数,方便地命名为 Objective。我也尝试过将 FGHI 组合成一个函数,但没有成功,所以我决定暂时这样。

def F(abcde):
    a, b, c, d, e = abcde
    return c - (b ** 2) / (a - e)

def G(abcde):
    a, b, c, d, e = abcde
    return (4 * e * ((a - e) * c - b ** 2)) / (a * c - b ** 2)

def H(abcde):
    a, b, c, d, e = abcde
    return b / (2 * (a - e))

def I(abcde):
    a, b, c, d, e = abcde
    return (2 * e * b) / (a * c - b ** 2)

def Objective(abcde):
    return (F(abcde) / G(abcde)) / (H(abcde) / I(abcde))

第三,为了简单起见,我将constraint(即(F/G)/(H/I)=1)和名为bnds的边界定义为初始猜测的+/- 10%

def constraint(x):
    F = x[0]
    G = x[1]
    H = x[2]
    I = x[3]
    return (F / G) / (H / I) - 1

con = {'type': 'eq', 'fun': constraint1}

min_per = 0.9
max_per = 1.1
bnds = ((A0*min_per, A0*max_per), (B0*min_per, B0*max_per), 
        (C0*min_per, C0*max_per), (D0*min_per, D0*max_per), 
        (E0*min_per, E0*max_per))

第四,也是最后,minimize 为我提供了一个名为 sol 的解决方案。

sol = minimize(Objective, ABCDE0, method='SLSQP', bounds=bnds, constraints=con1, options={'disp':True})

如果 sol 由 print(sol) 打印,将出现以下消息。

Positive directional derivative for linesearch    (Exit mode 8)
            Current function value: 1.0
            Iterations: 18
            Function evaluations: 188
            Gradient evaluations: 14
     fun: 1.0
     jac: array([ 0.00000000e+00,  1.49011612e-08, -7.45058060e-09,  0.00000000e+00,
        0.00000000e+00])
 message: 'Positive directional derivative for linesearch'
    nfev: 188
     nit: 18
    njev: 14
  status: 8
 success: False
       x: array([ 2.09      ,  5.76      , 10.53      ,  4.07      ,  2.50000277])

在我的新手看来,constraint 似乎是问题所在,但由于缺乏 minimize 的经验,我不确定。

请注意,D0d 不包含在任何函数中,但作为五个自变量之一在事物的宏伟计划中很重要。

这里发生了几件事:

首先,出于个人喜好,我可能会将函数 F、...、I 保留为具有多个输入以避免必须解压缩列表。 objective 函数确实需要一个列表作为它的参数;即你可以做类似

的事情
def F(a, b, c, d, e):
    return c - (b ** 2) / (a - e)

...

def objective(abcde):
    return (F(*abcde) / G(*abcde)) / (H(*abcde) / I(*abcde))

这就是风格。更重要的是,您的 constraint 方法不会完全按照您的意愿行事:据我了解,您想评估输入上的函数 F, ..., I ,但是永远不会发生;相反,变量 F 的值(这是一个不幸的名字,因为它掩盖了函数的名称)最终只是 a。相反,你会做类似

def constraint(x):
    return (F(*x) / G(*x)) / (H(*x) / I(*x)) - 1

现在,constraint(x) 只不过是 objective(x) - 1,因此您的约束最终表明您的 objective 在可行解中必须等于 1。这意味着实际上根本没有进行太多优化:任何可行的解决方案都是最优的。虽然先验的 minimize 确实会尝试为您找到一个可行的解决方案,但您可能会更幸运地尝试使用 scipy.optimizeroot-finding capabilities 中的一些作为您想要的正在尝试找到函数 objective - 1.

的根

现在终于,事实证明这很简单:你的函数 objective 在任何定义的地方都等于 1,所以 any 输入是一个可行的解决方案:首先,通过写 F = ((a-e)c - (b**2))/(a-e),注意 (a*c-b**2) / (4*e*(a-e))。那么,(F/G)*I = (2*e*b)/(4*e*(a-e)) = b/(2*(a-e)) = H,所以1 = (F/G)*(I/H) = (F/G)/(H/I).