web-dev-qa-db-ja.com

Python制約付き非線形最適化

pythonの制約付き非線形最適化の推奨パッケージは何ですか?

私が解決しようとしている特定の問題はこれです:

不明なX(Nx1)、M(Nx1)uベクトル、およびM(NxN)s行列があります。

max [5th percentile of (ui_T*X), i in 1 to M]
st 
0<=X<=1 and
[95th percentile of (X_T*si*X), i in 1 to M]<= constant

問題を始めたとき、usの推定値は1つしかなく、cvxpyで上記の問題を解決できました。

usの1つの推定値ではなく、値の分布全体を持っているので、分布全体を使用できるように目的関数を変更したいことに気付きました。上記の問題の説明は、意味のある方法でその情報を含めるための私の試みです。

cvxpyを使用してこれを解決することはできません。私はscipy.optimize.anneal、しかし、私は未知の値に境界を設定することができないようです。私もpulpを見ましたが、非線形制約を許可しません。

15
akhil

scipyには、制約付き非線形最適化のための素晴らしいパッケージがあります。

optimizedoc を読むことで開始できますが、SLSQPの例を次に示します。

minimize(func, [-1.0,1.0], args=(-1.0,), jac=func_deriv, constraints=cons, method='SLSQP', options={'disp': True})
12

scipy.optimize.minimizeSLSQPアルゴリズムは優れていますが、いくつかの制限があります。 1つ目はQPソルバーであるため、2次計画法のパラダイムにうまく適合する方程式に対して機能します。しかし、機能的な制約がある場合はどうなりますか?また、scipy.optimize.minimizeはグローバルオプティマイザーではないため、多くの場合、最終結果に非常に近い状態で開始する必要があります。

scipy.optimize自体とほぼ同じ長さの制約付き非線形最適化パッケージ(mysticと呼ばれます)があります-一般的な制約付き非線形最適化を処理するための頼りになる手段としてお勧めします。

たとえば、擬似コードを理解している場合、問題は次のようになります。

import numpy as np

M = 10
N = 3
Q = 10
C = 10

# let's be lazy, and generate s and u randomly...
s = np.random.randint(-Q,Q, size=(M,N,N))
u = np.random.randint(-Q,Q, size=(M,N))

def percentile(p, x):
    x = np.sort(x)
    p = 0.01 * p * len(x)
    if int(p) != p:
        return x[int(np.floor(p))]
    p = int(p)
    return x[p:p+2].mean()

def objective(x, p=5): # inverted objective, to find the max
    return -1*percentile(p, [np.dot(np.atleast_2d(u[i]), x)[0] for i in range(0,M-1)])


def constraint(x, p=95, v=C): # 95%(xTsx) - v <= 0
    x = np.atleast_2d(x)
    return percentile(p, [np.dot(np.dot(x,s[i]),x.T)[0,0] for i in range(0,M-1)]) - v

bounds = [(0,1) for i in range(0,N)]

したがって、mysticで問題を処理するには、境界と制約を指定するだけです。

from mystic.penalty import quadratic_inequality
@quadratic_inequality(constraint, k=1e4)
def penalty(x):
  return 0.0

from mystic.solvers import diffev2
from mystic.monitors import VerboseMonitor
mon = VerboseMonitor(10)

result = diffev2(objective, x0=bounds, penalty=penalty, npop=10, gtol=200, \
                 disp=False, full_output=True, itermon=mon, maxiter=M*N*100)

print result[0]
print result[1]

結果は次のようになります。

Generation 0 has Chi-Squared: -0.434718
Generation 10 has Chi-Squared: -1.733787
Generation 20 has Chi-Squared: -1.859787
Generation 30 has Chi-Squared: -1.860533
Generation 40 has Chi-Squared: -1.860533
Generation 50 has Chi-Squared: -1.860533
Generation 60 has Chi-Squared: -1.860533
Generation 70 has Chi-Squared: -1.860533
Generation 80 has Chi-Squared: -1.860533
Generation 90 has Chi-Squared: -1.860533
Generation 100 has Chi-Squared: -1.860533
Generation 110 has Chi-Squared: -1.860533
Generation 120 has Chi-Squared: -1.860533
Generation 130 has Chi-Squared: -1.860533
Generation 140 has Chi-Squared: -1.860533
Generation 150 has Chi-Squared: -1.860533
Generation 160 has Chi-Squared: -1.860533
Generation 170 has Chi-Squared: -1.860533
Generation 180 has Chi-Squared: -1.860533
Generation 190 has Chi-Squared: -1.860533
Generation 200 has Chi-Squared: -1.860533
Generation 210 has Chi-Squared: -1.860533
STOP("ChangeOverGeneration with {'tolerance': 0.005, 'generations': 200}")
[-0.17207128  0.73183465 -0.28218955]
-1.86053344078

mysticは非常に柔軟性があり、シンボリック制約および機能制約を含むあらゆるタイプの制約(等式、不等式)を処理できます。上記の「ペナルティ」として制約を指定しました。これは、制約に違反した場合に目標にペナルティを適用するという点で、従来の方法です。 mysticは、非線形カーネル変換も提供します。これは、有効なソリューションのスペースを削減することでソリューション空間を制約します(つまり、空間マッピングまたはカーネル変換によって)。

例として、制約が制約行列の形式ではないため、多くのQPソルバーを壊す問題を解くmysticがあります。圧力容器の設計を最適化しています。

"Pressure Vessel Design"

def objective(x):
    x0,x1,x2,x3 = x
    return 0.6224*x0*x2*x3 + 1.7781*x1*x2**2 + 3.1661*x0**2*x3 + 19.84*x0**2*x2

bounds = [(0,1e6)]*4
# with penalty='penalty' applied, solution is:
xs = [0.72759093, 0.35964857, 37.69901188, 240.0]
ys = 5804.3762083

from mystic.symbolic import generate_constraint, generate_solvers, simplify
from mystic.symbolic import generate_penalty, generate_conditions

equations = """
-x0 + 0.0193*x2 <= 0.0
-x1 + 0.00954*x2 <= 0.0
-pi*x2**2*x3 - (4/3.)*pi*x2**3 + 1296000.0 <= 0.0
x3 - 240.0 <= 0.0
"""
cf = generate_constraint(generate_solvers(simplify(equations)))
pf = generate_penalty(generate_conditions(equations), k=1e12)


if __name__ == '__main__':

    from mystic.solvers import diffev2
    from mystic.math import almostEqual
    from mystic.monitors import VerboseMonitor
    mon = VerboseMonitor(10)

    result = diffev2(objective, x0=bounds, bounds=bounds, constraints=cf, penalty=pf, \ 
                     npop=40, gtol=50, disp=False, full_output=True, itermon=mon)

    assert almostEqual(result[0], xs, rel=1e-2)
    assert almostEqual(result[1], ys, rel=1e-2)

これを見つけて、そのようなおよそ100の例をここで見つけてください: https://github.com/uqfoundation/mystic

私は著者なので、少し偏見があります。ただし、バイアスは非常にわずかです。 mysticは成熟しており、十分にサポートされており、厳しい制約のある非線形最適化問題を解決する能力において並ぶものがありません。

11
Mike McKerns

他の人もコメントしているように、SciPy最小化パッケージは開始するのに適した場所です。以下に、目的関数、等式制約、および不等式制約を含む例を示します(Hock Schittkowski#71ベンチマーク)。

import numpy as np
from scipy.optimize import minimize

def objective(x):
    return x[0]*x[3]*(x[0]+x[1]+x[2])+x[2]

def constraint1(x):
    return x[0]*x[1]*x[2]*x[3]-25.0

def constraint2(x):
    sum_eq = 40.0
    for i in range(4):
        sum_eq = sum_eq - x[i]**2
    return sum_eq

# initial guesses
n = 4
x0 = np.zeros(n)
x0[0] = 1.0
x0[1] = 5.0
x0[2] = 5.0
x0[3] = 1.0

# show initial objective
print('Initial SSE Objective: ' + str(objective(x0)))

# optimize
b = (1.0,5.0)
bnds = (b, b, b, b)
con1 = {'type': 'ineq', 'fun': constraint1} 
con2 = {'type': 'eq', 'fun': constraint2}
cons = ([con1,con2])
solution = minimize(objective,x0,method='SLSQP',\
                    bounds=bnds,constraints=cons)
x = solution.x

# show final objective
print('Final SSE Objective: ' + str(objective(x)))

# print solution
print('Solution')
print('x1 = ' + str(x[0]))
print('x2 = ' + str(x[1]))
print('x3 = ' + str(x[2]))
print('x4 = ' + str(x[3]))

SLSQPで問題を解決できない場合は、 Pythonの非線形プログラミングソルバー に関するより包括的なディスカッションスレッドもあります。 Engineering Design Optimization に関する私の教材は、ソルバーのメソッドに関する追加情報が必要な場合に利用できます。

4
John Hedengren

通常、フィッティングには _scipy.optimize_ 関数、または lmfit を使用できます。これは、scipy.optimizeパッケージを単純に拡張して、境界。個人的に、私は kmpfit を使用するのが好きです。これはkapteynライブラリの一部であり、MPFITのC実装に基づいています。

scipy.optimize.minimize()はおそらく最も入手しやすく、一般的に使用されています。

3
pseudocubic