簡體   English   中英

Python - 使用 scipy.minimize 最小化約束 function 的問題

[英]Python - Problem minimizing a constrained function with scipy.minimize

我試圖最小化采用算法scipy.optimize.minimize function 涉及最小化3*N參數,其中N是輸入。 更具體地說,我的最小化參數在三個 arrays H = H[0],H[1],...,H[N-1] , a = a[0],a[1],...,a[N-1]給出a = a[0],a[1],...,a[N-1]b = b[0],b[1],...,b[N-1]我僅將它們連接到一個名為mins的數組中,其中len(mins)=3*N

這些參數也受到如下約束:

0 <= H  and  sum(H) = 0.5
0 <= a <= Pi/2
0 <= b <= Pi/2

因此,我的約束代碼如下:

import numpy as np

# constraints on x:
def Hlhs(mins):    # left hand side
    return np.diag(np.ones(N)) @ mins.reshape(3,N)[0]
def Hrhs(mins):    # right hand side
    return np.sum(mins.reshape(3,N)[0]) - 0.5
con1H = {'type': 'ineq', 'fun': lambda H: Hlhs(H)}
con2H = {'type': 'eq', 'fun': lambda H: Hrhs(H)}

# constraints on a:
def alhs(mins):
    return np.diag(np.ones(N)) @ mins.reshape(3,N)[1]
def arhs(mins): 
    return -np.diag(np.ones(N)) @ mins.reshape(3,N)[1] + (np.ones(N))*np.pi/2
con1a = {'type': 'ineq', 'fun': lambda a: alhs(a)}
con2a = {'type': 'ineq', 'fun': lambda a: arhs(a)}

# constraints on b:
def blhs(mins):
    return np.diag(np.ones(N)) @ mins.reshape(3,N)[2]
def brhs(mins): 
    return -np.diag(np.ones(N)) @ mins.reshape(3,N)[2] + (np.ones(N))*np.pi/2
con1b = {'type': 'ineq', 'fun': lambda b: blhs(b)}
con2b = {'type': 'ineq', 'fun': lambda b: brhs(b)}

我的 function 將其他參數(並采用N=3 )最小化,由(如果太長,我很抱歉)給出:

gamma = 17      
C = 85         
T = 0         
Hf = 0.5         
Li = 2         
Bi = 1  
         
N = 3            

def FUN(mins):
    H, a, b = mins.reshape(3,N)
    S1 = 0; S2 = 0
    B = np.zeros(N); L = np.zeros(N);   
    for i in range(N):
        sbi=Bi; sli=Li
        for j in range(i+1):
            sbi += 2*H[j]*np.tan(b[j])
            sli += 2*H[j]*np.tan(a[j])
        B[i]=sbi
        L[i]=sli    
    for i in range(N):
        S1 += (C*(1-np.sin(a[i])) + T*np.sin(a[i])) * (Bi*H[i]+H[i]**2*np.tan(b[i]))/np.cos(a[i]) + \
        (C*(1-np.sin(b[i])) + T*np.sin(b[i])) * (Li*H[i]+H[i]**2*np.tan(a[i]))/np.cos(b[i])    
    S2 += (gamma*H[0]/12)*(Bi*Li + 4*(B[0]-H[0]*np.tan(b[0]))*(L[0]-H[0]*np.tan(a[0])) + B[0]*L[0])
    j=1 
    while j<(N):
        S2 += (gamma*H[j]/12)*(B[j-1]*L[j-1] + 4*(B[j]-H[j]*np.tan(b[j]))*(L[j]-H[j]*np.tan(a[j])) + B[j]*L[j])
        j += 1
    F = 2*(S1+S2)
    return F

最后,采用初始猜測值作為 0,最小化由下式給出:

x0 = np.zeros(3*N)
res = scipy.optimize.minimize(FUN,x0,constraints=(con1H,con2H,con1a,con2a,con1b,con2b),tol=1e-25)

我的問題是:

a)觀察結果res ,即使我有約束使它們為正,一些值也變為負值。 最小化的成功是False ,消息是: Positive directional derivative for linesearch 此外,結果與預期的最小值相差甚遠。

b) 采用method='trust-constr'我得到的值更接近於我的預期,但失敗了,並且消息The maximum number of function evaluations is exceeded. . 有什么辦法可以改善這一點嗎?

我知道有一個最小值非常接近這些值:

H = [0.2,0.15,0.15]
a = [1.0053,1.0053,1.2566]
b = [1.0681,1.1310,1.3195]

其中 function 的值為123,45 我已經檢查了 function 幾次,它似乎工作正常。 誰能幫我找出我的問題在哪里? 我試圖改變xtolmaxiter但沒有成功。 先感謝您!

這里有一些提示:

  • 您的初始點x0不可行,因為它不滿足約束sum(H) = 0.5 提供一個可行的初始點應該可以解決您的第一個問題。

  • 除了約束sum(H) = 0.5 ,所有約束都是變量的簡單界限。 一般來說,建議minimize minimum 的bounds參數傳遞變量邊界。 您可以像這樣簡單地定義並傳遞所有邊界

from scipy.optimize import minimize
import numpy as np

# ..your variables and functions ..

bounds = [(0, None)]*N + [(0, np.pi/2)]*2*N

x0 = np.zeros(3*N)
x0[0] = 0.5

res = minimize(FUN, x0, constraints=(con2H,), bounds=bounds,
               method="trust-constr", options={'maxiter': 20000})

其中每個元組包含每個變量的下限和上限。

  • 不幸的是,'trust-constr' 仍然難以收斂到局部最小化器。 在這種情況下,您可以嘗試其他初始點,也可以使用最先進的開源求解器 Ipopt。 Cython 包裝器cyipopt提供類似於 scipy 的接口:
from cyipopt import minimize_ipopt

# rest as above

res = minimize_ipopt(FUN, x0, constraints=(con2H,), bounds=bounds)

這給了我一個目標值為 122.9 的解決方案。

  • 最后但並非最不重要的一點是,提供精確的梯度、雅可比和粗麻布始終是一個好主意。

暫無
暫無

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

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