Main Content

最適化式の初期化

このトピックでは、最適化式が適切に初期化されていない場合に発生するエラーについて説明し、エラーに対処するさまざまな方法の例を示します。

式のエラー

目的関数または非線形制約関数やそれらの式から、次のエラーを受け取ることがあります。

Unable to perform assignment because value of type 'optim.problemdef.OptimizationExpression' is not convertible
to 'double'.

多くの場合、このエラーは最適化式が正しく初期化されていないことに起因しています。通常、変数 F は、次のようにゼロの配列を宣言して標準ループ内で初期化します。

F = zeros(N,1);

しかし、F が最適化式の場合は、optimexpr を使用して初期化する必要があります。

F = optimexpr(N,1);

このトピックでは、適切な初期化方法の例を示します。どの方法も、内部ループを使用する関数の同じ例に基づいています。

function f = myFun(x)
out = zeros(size(x));
out(1) = x(1);
for i = 2:10
    out(i) = (x(i) - x(i-1))^3;
end
f = mean(out);
end

最適化変数 x の目的関数として myFun(x) を使用しようとすると、次のようなエラーが発生します。

x = optimvar("x",10,LowerBound=0,UpperBound=10);
prob = optimproblem(Objective=myFun(x));
Unable to perform assignment because value of type 'optim.problemdef.OptimizationVariable' is not convertible
to 'double'.

Error in myFun (line 3)
out(1) = x(1);

Caused by:
    Error using double
    Conversion to double from optim.problemdef.OptimizationVariable is not possible.

ただし、myFun はソルバーベースの問題では目的関数として機能します。

rng default
x0 = 10*rand(10,1);
lb = zeros(10,1);
ub = 10 + lb;
[sol,fval] = fmincon(@myFun,x0,[],[],[],[],lb,ub)
Local minimum found that satisfies the constraints.

Optimization completed because the objective function is non-decreasing in 
feasible directions, to within the value of the optimality tolerance,
and constraints are satisfied to within the value of the constraint tolerance.

sol =

    9.4226
   10.0000
    0.0000
    5.0000
   10.0000
    0.0000
    3.3333
    6.6667
   10.0000
    0.0000


fval =

 -262.9274

この問題にはいくつかの局所的な解があるため、初期点によって異なる解が得られる可能性があります。

"like" 構文の使用による配列の初期化

zeros に対して引数 "like" を使用するように関数を書き換えます。このようにすると、最適化式または数値配列を入力として渡すことができます。

この方法にはいくつかの利点があります。

  • 関数シグネチャが維持される。

  • 解法プロセスで実行される余分なコードが導入されない。

  • 該当する場合は自動微分が有効になる。

  • ソルバーベースと問題ベースのいずれのワークフローでも関数を使用できる。

  • fcn2optimexpr を使用するときに静的解析が有効になる。静的解析の詳細については、最適化式の静的解析を参照してください。

function f = myFun1(x)
out = zeros(size(x),"like",x);
out(1) = x(1);
for i = 2:10
    out(i) = (x(i) - x(i-1))^3;
end
f = mean(out);
end

問題ベースのワークフローで myFun1 を使用します。

x = optimvar("x",10,LowerBound=0,UpperBound=10);
prob = optimproblem(Objective=myFun1(x));
rng default
x0.x = 10*rand(10,1);
[sol,fval] = solve(prob,x0)
Solving problem using fmincon.

Local minimum found that satisfies the constraints.

Optimization completed because the objective function is non-decreasing in 
feasible directions, to within the value of the optimality tolerance,
and constraints are satisfied to within the value of the constraint tolerance.

sol = 

  struct with fields:

    x: [10×1 double]


fval =

 -262.9274

ソルバーベースのワークフローで myFun1 を使用します。

rng default
x0 = 10*rand(10,1);
lb = zeros(10,1);
ub = 10 + lb;
[sol,fval] = fmincon(@myFun1,x0,[],[],[],[],lb,ub)
Local minimum found that satisfies the constraints.

Optimization completed because the objective function is non-decreasing in 
feasible directions, to within the value of the optimality tolerance,
and constraints are satisfied to within the value of the constraint tolerance.

sol =

    9.4226
   10.0000
    0.0000
    5.0000
   10.0000
    0.0000
    3.3333
    6.6667
   10.0000
    0.0000


fval =

 -262.9274

関数の変更による初期配列の受け入れ

追加引数として初期値を受け入れるように、関数を書き換えます。このようにすると、最適化式または数値配列を初期値として渡すことができます。myFun2 は入力変数 out を出力変数として使用し、ゼロ配列または最適化式のいずれかを受け入れます。

この方法にはいくつかの利点があります。

  • 該当する場合は自動微分が有効になる。

  • 解法プロセスで実行される余分なコードが導入されない。

  • ソルバーベースと問題ベースのいずれのワークフローでも関数を使用できる。

  • fcn2optimexpr を使用するときに静的解析が有効になる。静的解析の詳細については、最適化式の静的解析を参照してください。

この方法の欠点は、別の関数シグネチャで関数を書き換える必要があることです。

function f = myFun2(out,x)
out(1) = x(1);
for i = 2:10
    out(i) = (x(i) - x(i-1))^3;
end
f = mean(out);
end

問題ベースのワークフローで myFun2 を使用します。

x = optimvar("x",10,LowerBound=0,UpperBound=10);
out = optimexpr(size(x));
prob = optimproblem(Objective=myFun2(out,x));
rng default
x0.x = 10*rand(10,1);
[sol,fval] = solve(prob,x0)
Solving problem using fmincon.

Local minimum found that satisfies the constraints.

Optimization completed because the objective function is non-decreasing in 
feasible directions, to within the value of the optimality tolerance,
and constraints are satisfied to within the value of the constraint tolerance.

sol = 

  struct with fields:

    x: [10×1 double]


fval =

 -262.9274

ソルバーベースのワークフローで myFun2 を使用します。

rng default
x0 = 10*rand(10,1);
lb = zeros(10,1);
ub = 10 + lb;
out = zeros(size(x0));
[sol,fval] = fmincon(@(x)myFun2(out,x),x0,[],[],[],[],lb,ub)
Local minimum found that satisfies the constraints.

Optimization completed because the objective function is non-decreasing in 
feasible directions, to within the value of the optimality tolerance,
and constraints are satisfied to within the value of the constraint tolerance.

sol =

    9.4226
   10.0000
    0.0000
    5.0000
   10.0000
    0.0000
    3.3333
    6.6667
   10.0000
    0.0000


fval =

 -262.9274

関数の書き換えによる適切な式の初期化

問題変数のタイプを明示的にチェックすると、式を適切に初期化することができます。この方法にはいくつかの利点があります。

  • 該当する場合は自動微分が有効になる。

  • ソルバーベースと問題ベースのいずれのワークフローでも関数を使用できる。

この方法の欠点は、関数を書き換える必要があること、ソルバーの実行中にわずかなオーバーヘッドが発生すること、if ステートメントがあるため fcn2optimexpr を使用するときに静的解析がサポートされないということです。静的解析の詳細については、最適化式の静的解析を参照してください。

function f = myFun3(x)
% Check for the data type of variable x
if isa(x,'double')
    out = zeros(size(x));
else
    out = optimexpr(size(x));
end
% No changes to the rest of the code
out(1) = x(1);
for i = 2:10
    out(i) = (x(i) - x(i-1))^3;
end
f = mean(out);
end

最適化変数および目的関数 myFun3 を使用して、問題を解きます。

x = optimvar("x",10,LowerBound=0,UpperBound=10);
prob = optimproblem(Objective=myFun3(x));
rng default
x0.x = 10*rand(10,1);
[sol,fval] = solve(prob,x0)
Solving problem using fmincon.

Local minimum found that satisfies the constraints.

Optimization completed because the objective function is non-decreasing in 
feasible directions, to within the value of the optimality tolerance,
and constraints are satisfied to within the value of the constraint tolerance.

sol = 

  struct with fields:

    x: [10×1 double]


fval =

 -262.9274

fmincon および目的関数 myFun3 を使用して、問題を解きます。

rng default
x0 = 10*rand(10,1);
lb = zeros(10,1);
ub = 10 + lb;
out = zeros(size(x0));
[sol,fval] = fmincon(@myFun3,x0,[],[],[],[],lb,ub)
Local minimum found that satisfies the constraints.

Optimization completed because the objective function is non-decreasing in 
feasible directions, to within the value of the optimality tolerance,
and constraints are satisfied to within the value of the constraint tolerance.

sol =

    9.4226
   10.0000
    0.0000
    5.0000
   10.0000
    0.0000
    3.3333
    6.6667
   10.0000
    0.0000


fval =

 -262.9274

fcn2optimexpr 変換の使用

R2022b 以降では、fcn2optimexpr を使用して目的関数を最適化式に変換し、その式を標準のゼロ配列を使用して初期化できます。

この方法にはいくつかの利点があります。

  • 関数シグネチャが維持される。

  • 該当する場合は自動微分が有効になる。

  • ソルバーベースと問題ベースのいずれのワークフローでも関数を使用できる。

この方法には静的解析が必要なため、MATLAB® の以前のバージョンでは正しく実行されない可能性があるほか、わずかなオーバーヘッドが発生することがあります。この例では式のエラーで示した元の関数 myFun を使用しており、問題ベースのワークフローでは失敗します。

x = optimvar("x",10,LowerBound=0,UpperBound=10);
obj = fcn2optimexpr(@myFun,x,Display="on");
prob = optimproblem(Objective=obj);
rng default
x0.x = 10*rand(10,1);
[sol,fval] = solve(prob,x0)
The function uses only supported operators. The returned expressions use the operators on the problem variables.

Solving problem using fmincon.

Local minimum found that satisfies the constraints.

Optimization completed because the objective function is non-decreasing in 
feasible directions, to within the value of the optimality tolerance,
and constraints are satisfied to within the value of the constraint tolerance.

sol = 

  struct with fields:

    x: [10×1 double]


fval =

 -262.9274

参考

|

関連するトピック