10. 非線形最適化 (多次元)

XLPackによる多次元の非線形最適化問題の解き方、すなわち、一般の多変数非線形関数 f(x1, x2, …, xn) の最小点の求め方の例を示します。

例題

次の関数の最小点を求める。

    f(x1, x2) = 100(x2 - x12)2 + (1 - x1)2

関数の形は次のようになります(縦軸は対数値で表しています)。

10-01

この関数は、Rosenbrockの関数と呼ばれ、(-1.2, 1) を出発点として、最小点 (1, 1) を求めるテスト問題としてよく使用されます。深い曲がった谷の中に最小点があり、最小点に到達するのが難しいとされています。

VBAプログラムを使用した解き方 (1)

VBAサブルーチンOptif0を使ったプログラム例を示します。

Sub F(N As Long, X() As Double, Fval As Double)
    Fval = 100 * (X(1) - X(0) ^ 2) ^ 2 + (1 - X(0)) ^ 2
End Sub

Sub Start()
    Const NMax = 10, NData = 5
    Dim N As Long, X(NMax) As Double, Xpls(NMax) As Double, Fpls As Double
    Dim Info As Long, I As Long
    N = 2
    For I = 0 To NData - 1
        '--- Input data
        X(0) = Cells(5 + I, 1): X(1) = Cells(5 + I, 2)
        '--- Find min point of equation
        Call Optif0(N, X(), AddressOf F, Xpls(), Fpls, Info)
        '--- Output result
        Cells(5 + I, 3) = Xpls(0): Cells(5 + I, 4) = Xpls(1): Cells(5 + I, 5) = Info
    Next
End Sub

目的関数を外部サブルーチンとして用意し、初期値を指定してOptif0を呼び出します。Optif0は、初期値として与えられた近似解を出発点に反復計算を行い、その近傍の最小点を求めます。

初期値としては、(-1.2, 1) の他に (-1, 1)、 (-1, -1)、(0, 1)、(0, 0) を試してみます。

このプログラムを実行すると、次の結果が得られました。

(-1, 1)のように初期値によっては収束しない場合がありました。上の例はテスト問題のため、あえて収束しにくい初期値を与えていますが、実際に使う際にはできるだけよい初期値を与えるべきです。問題によっては局所的な最小点をいくつも持つものがあり、目的の解以外の局所最小点に収束してしまうことがあります。

VBAプログラムを使用した解き方 (2)

リバースコミュニケーション版のVBAサブルーチンOptif0_rを使ったプログラム例を示します。

Sub Start()
    Const NMax = 10, NData = 5
    Dim N As Long, X(NMax) As Double, Xpls(NMax) As Double, Fpls As Double
    Dim Info As Long, I As Long
    Dim XX(NMax - 1) As Double, YY As Double, IRev As Long
    N = 2
    For I = 0 To NData - 1
        '--- Input data
        X(0) = Cells(5 + I, 1): X(1) = Cells(5 + I, 2)
        '--- Find min point of equation
        IRev = 0
        Do
            Call Optif0_r(N, X(), Xpls(), Fpls, Info, XX(), YY, IRev)
            If IRev <> 1 Then YY = 100 * (XX(1) - XX(0) ^ 2) ^ 2 + (1 - XX(0)) ^ 2
        Loop While IRev <> 0
        '--- Output result
        Cells(5 + I, 3) = Xpls(0): Cells(5 + I, 4) = Xpls(1): Cells(5 + I, 5) = Info
    Next
End Sub

目的関数を外部関数として与えるのではなく、IRev = 1のときにXX()の値を使って関数値を計算しYYに入れて再度Optif0_rを呼び出します。リバースコミュニケーション版の詳細についてはこちらを参照してください。

このプログラムを実行すると上と同じ結果が得られます。

Top