nAG数値計算ライブラリ
> 最適化アルゴリズムExample集
> 密な非線形最小二乗問題の逐次二次計画法による解法
非線形最小二乗問題(逐次二次計画法-SQPを利用、密)
このExampleは、非線形最小二乗問題を逐次二次計画法(SQP)を利用して解いています。Hock and Schittkowskiの’Test Examples for Nonlinear Scripting Codes’から問題57を取り上げ、二乗和の最小化を行っています。目的関数の関数値と一次導関数を使用しながら、密な行列を用いたアクティブセットSQP法により最適解を求めています。
目的関数:
タスク | 式 |
---|---|
Minimize | \(\sum_{i=0}^{43} \left(x_0 + (0.49 - x_0) \exp(-x_1(a_i - 8))\right)^2\) |
ここで、\(a_i\) (\(i=0,1,\ldots,43\)) は与えられた44個の定数で、8から42の範囲の値を取ります。目的は、これらの定数に対する予測値と実測値の二乗誤差の和を最小化することです。
決定変数:
変数 | 範囲 |
---|---|
\(x_0\) | \([0.4, 10^{25}]\) |
\(x_1\) | \([-4.0, 10^{25}]\) |
制約条件:
制約 | 式 |
---|---|
線形制約 | \(x_0 + x_1 \geq 1\) |
非線形制約 | \(0.49 x_1 - x_0 x_1 \geq 0.09\) |
問題には1つの線形制約と1つの非線形制約があります。線形制約は決定変数の和が1以上であることを要求し、非線形制約は決定変数の積に関する条件を課しています。
Exampleの実行コマンド:
python -m naginterfaces.library.examples.opt.lsq_gencon_deriv_ex
ソースコード表示コマンド:
python -c "import inspect; from naginterfaces.library.examples.opt import lsq_gencon_deriv_ex; print(''.join(inspect.getsourcelines(lsq_gencon_deriv_ex)[0]))"
出力結果例:
naginterfaces.library.opt.lsq_gencon_deriv Python Example Results.
Minimizing Problem 57 from Hock and Schittkowski's
'Test Examples for Nonlinear Scripting Codes'.
Final function value is 1.42298348615e-02.
マニュアル:
ソース:
#!/usr/bin/env python3
"``naginterfaces.library.opt.lsq_gencon_deriv`` Python Example."
# nAG Copyright 2018-2019.
# pylint: disable=invalid-name,too-many-arguments,too-many-locals
from math import exp
import numpy as np
from naginterfaces.library import opt
def main():
"""
Example for :func:`naginterfaces.library.opt.lsq_gencon_deriv`.
Minimum of a sum of squares, nonlinear constraints, dense, active-set SQP
method, using function values and optionally first derivatives.
>>> main()
naginterfaces.library.opt.lsq_gencon_deriv Python Example Results.
Minimizing Problem 57 from Hock and Schittkowski's
'Test Examples for Nonlinear Scripting Codes'.
Final function value is 1.42298348615e-02.
"""
print(
'naginterfaces.library.opt.lsq_gencon_deriv Python Example Results.'
)print('Minimizing Problem 57 from Hock and Schittkowski\'s')
print('\'Test Examples for Nonlinear Scripting Codes\'.')
def cb_confun(mode, needc, x, cjac, nstate):
"The nonlinear constraint and its first derivatives."
if needc[0] <= 0 or mode == 1:
= [0.]*len(needc)
c elif mode in [0, 2]:
= [0.49*x[1] - x[0]*x[1]]
c
if needc[0] <= 0:
return c
if mode in [1, 2]:
0, 0] = -x[1]
cjac[0, 1] = -x[0] + 0.49
cjac[
return c
def cb_objfun(mode, needfi, x, fjac, nstate):
"""
The (two-variable) sum of squares function to minimize,
and its first derivatives.
"""
# The set of 44 'a' data values:
= [
a 8., 8., 10., 10., 10., 10., 12., 12., 12.,
12., 14., 14., 14., 16., 16., 16., 18., 18.,
20., 20., 20., 22.,
22., 22., 24., 24., 24., 26., 26., 26., 28.,
28., 30., 30., 30., 32., 32., 34., 36., 36.,
38., 38., 40., 42.,
]= fjac.shape[0]
m = np.empty(m)
f
for fi in range(m):
= exp(-x[1]*(a[fi] - 8.))
exp_term
if needfi == fi + 1 or mode in [0, 2]:
= x[0] + (0.49 - x[0])*exp_term
f[fi]
if needfi == fi + 1:
return f
if mode in [1, 2]:
0] = 1. - exp_term
fjac[fi, 1] = -(0.49 - x[0])*(a[fi] - 8.)*exp_term
fjac[fi,
return f
# Initialize the communication structure:
= opt.nlp1_init('lsq_gencon_deriv')
comm
# The configuration for this problem.
# One nonlinear constraint (defined by confun):
= 1
ncnln # The linear constraints:
= [[1., 1.]]
a # The bounds on x and on the constraints:
= [0.4, -4., 1., 0.09]
bl # 'Infinite' upper bounds:
= [1.e25]*len(bl)
bu # The coefficients of the constant vector in the objective:
= [
y 0.49, 0.49, 0.48, 0.47, 0.48, 0.47, 0.46, 0.46, 0.45, 0.43, 0.45,
0.43, 0.43, 0.44, 0.43, 0.43, 0.46, 0.45, 0.42, 0.42, 0.43, 0.41,
0.41, 0.40, 0.42, 0.40, 0.40, 0.41, 0.40, 0.41, 0.41, 0.40, 0.40,
0.40, 0.38, 0.41, 0.40, 0.40, 0.41, 0.38, 0.40, 0.40, 0.39, 0.39
]# Initial estimate of the solution:
= [0.4, 0.]
x = len(x)
n # Zero the initial nonlinear-constraint Jacobian, which has an effect
# here because of the default setting of 'Derivative Level' (level 3):
= np.zeros((ncnln, n))
cjac
# Solve the problem:
= opt.lsq_gencon_deriv(
objf =a, confun=cb_confun, cjac=cjac,
bl, bu, y, cb_objfun, x, comm, a
).objf
print('Final function value is {:.11e}.'.format(objf))
if __name__ == '__main__':
main()import doctest
import sys
sys.exit(
doctest.testmod(None, verbose=True, report=False,
=doctest.ELLIPSIS | doctest.REPORT_NDIFF,
optionflags
).failed )