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

注 – 例題ワークシートをダウンロードすることができます. 1. 例題ワークシートの入手と使用方法 をご覧ください.


多次元の非線形最適化問題の 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(6 + I, 1): X(1) = Cells(6 + I, 2)
        '--- Find min point of equation
        Call Optif0(N, X(), AddressOf F, Xpls(), Fpls, Info)
        '--- Output result
        Cells(6 + I, 3) = Xpls(0): Cells(6 + I, 4) = Xpls(1): Cells(6 + I, 5) = Info
    Next
End Sub

目的関数を外部サブルーチンとして用意し, 初期値を指定して Optif0 を呼び出します. Optif0 は, 初期値として与えられた近似解を出発点に反復計算を行い, その近傍の最小点を求めます. ここでは, 5 つの異なる初期値を与えたときにどのような解が得られるかを見るプログラムとしています.

初期値としては, (-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(6 + I, 1): X(1) = Cells(6 + 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(6 + I, 3) = Xpls(0): Cells(6 + I, 4) = Xpls(1): Cells(6 + I, 5) = Info
    Next
End Sub

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

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

ソルバーを使用した解き方

XLPackソルバーアドインの「多変数非線形最適化」を使って解くこともできます. B9セルに数式 (=100*(C8-B8^2)^2+(1-B8)^2) が入力されています.

ソルバーについては こちら も参照ください.