読者です 読者をやめる 読者になる 読者になる

旅行好きなソフトエンジニアの備忘録

プログラミングや技術関連のメモを始めました

【C#】 ペナルティ法による制約条件付き最適化

制約条件が付いた最適化問題をペナルティ法を使って解いてみます。ここでは例として
制約条件:x_0+2x_1 > 2
を満たす上で
目的関数:f(x_0,x_1)=4x_0^2+x_1^2
の最小値を与えるx_0, x_1を求めます。

まずは目的関数、制約条件、ペナルティ係数から新しい目的関数を作成するクラスを作成します。

public class PenaltyFunctionMethod
{
    public static Func<double[], double> CreateObjectiveFunction(Func<double[], double> f, Func<double[], double> penaltyFunction, double penalty)
    {
        return x => f(x) + penalty*penaltyFunction(x);
    }
}

次にPenaltyFunctionMethodクラスで作成した新しい目的関数の最小化をSteepestDescentMethodMVクラス(【C#】 最急降下法による多変数関数の最適化 - 旅行好きなソフトエンジニアの備忘録)を使って行います。 罰金関数についてですが、制約条件から
x_0+2x_1 \leqq 2の時 ⇒ 2-(x_0+2x_1)
x_0+2x_1 > 2の時 ⇒ 0
となります。

// 目的関数
Func<double[], double> objectiveFunction = x => 4.0*x[0]*x[0] + x[1]*x[1];
// 罰金関数
Func<double[], double> penaltyFunction = x =>
{
    if (x[0] + 2.0*x[1] <= 2.0)
    {
        return 2.0 - (x[0] + 2.0*x[1]);
    }
    else
    {
        return 0.0;
    }
};
// ペナルティ係数
double penalty = 10.0;
// 罰金関数を考慮した新しい目的関数を作成する
Func<double[], double> newObjectiveFunction = PenaltyFunctionMethod.CreateObjectiveFunction(objectiveFunction, penaltyFunction, penalty);

// 初期値を(x0, x1)=(3.7, 3.7)とする
var initialX = new double[] { 3.7, 3.7 };
// 計算回数
int iteration = 200;
// 学習係数
double learningRate = 0.01;
// 新しい目的関数に対して最小値を求める
double[] answer = SteepestDescentMethodMV.Compute(newObjectiveFunction, initialX, iteration, learningRate);

実行してみると分かるのですが、ペナルティ係数と学習係数の調整が難しく、そもそもこの手法自体あまり優れた解法ではないようです。 とはいえせっかく勉強したのでひとまずメモしておきます。

工学のための最適化手法入門 (工学のための数学)

工学のための最適化手法入門 (工学のための数学)


関連記事
【C#】 ラグランジュの未定乗数法による制約条件付き最適化 - 旅行好きなソフトエンジニアの備忘録