制約付き非線形最小二乗の lsqnonlin
と fmincon
の比較
この例では、制約付き最小二乗問題を解く際、一般的に lsqnonlin
は fmincon
よりも関数評価の回数が少ないことを示します。どちらのソルバーも、fmincon
'interior-point'
アルゴリズムを使用して問題を解きます。しかし、通常は lsqnonlin
の方が少ない関数評価で問題を解きます。これは、lsqnonlin
の方が処理する情報が多いためです。fmincon
は として指定された二乗和を最小化します。ここで、 はベクトル関数です。これに対し、lsqnonlin
はベクトル 全体を処理するため、和のすべての成分にアクセスできます。言い換えれば、fmincon
は和の値にのみアクセスできますが、lsqnonlin
は各成分に個別にアクセスできます。
この例の最後にリストされている補助関数 runlsqfmincon
は、1 から 50 までの について、非線形制約のあるスケーリングされた Rosenbrock タイプの一連の問題を作成します。ここで、問題の変数の数は です。Rosenbrock 関数の詳細については、制約付き非線形問題の解法、問題ベースを参照してください。また、この関数は結果をプロットして以下を表示します。
反復回数
関数カウント
結果として得られる残差
このプロットは、有限差分導関数の推定値 (ラベル付き FD) と、自動微分を使用して計算された導関数の差を示します。自動微分の詳細については、自動微分の背景を参照してください。
runlsqfmincon;
このプロットは以下の結果を示します。これらは一般的なものです。
各 について、
fmincon
の反復回数はlsqnonlin
の 2 倍より多く、 に対してほぼ線形に増加します。反復回数は導関数の推定方法に依存しません。
有限差分 (FD) 推定の関数カウントは、自動微分よりもはるかに多くなります。
導関数の推定方法が同じである場合、
lsqnonlin
の関数カウントはfmincon
よりも少なくなります。残差はすべての解法で一致します。これは、結果がソルバーや導関数の推定方法に依存しないことを意味します。
この結果は、反復回数と関数カウントの両方において lsqnonlin
が fmincon
よりも効率的であることを示しています。ただし、問題が異なれば結果も異なり、問題によっては fmincon
が lsqnonlin
よりも効率的なこともあります。
補助関数
次のコードは、補助関数 runlsqfmincon
を作成します。
function [lsq,lsqfd,fmin,fminfd] = runlsqfmincon() optslsq = optimoptions("lsqnonlin",Display="none",... MaxFunctionEvaluations=1e5,MaxIterations=1e4); % Allow for many iterations and Fevals optsfmincon = optimoptions("fmincon",Display="none",... MaxFunctionEvaluations=1e5,MaxIterations=1e4); % Create structures to hold results z = zeros(1,50); lsq = struct('Iterations',z,'Fcount',z,'Residual',z); lsqfd = lsq; fmin = lsq; fminfd = lsq; rng(1) % Reproducible initial points x00 = -1/2 + randn(50,1); y00 = 1/2 + randn(50,1); for N = 1:50 x = optimvar("x",N,LowerBound=-3,UpperBound=3); y = optimvar("y",N,LowerBound=0,UpperBound=9); prob = optimproblem("Objective",sum((10*(y - x.^2)).^2 + (1 - x).^2)); x0.x = x00(1:N); x0.y = y00(1:N); % Include a set of nonlinear inequality constraints cons = optimconstr(N); for i = 1:N cons(i) = x(i)^2 + y(i)^2 <= 1/2 + 1/8*i; end prob.Constraints = cons; [sol,fval,exitflag,output] = solve(prob,x0,Options=optslsq); lsq.Iterations(N) = output.iterations; lsq.Fcount(N) = output.funcCount; lsq.Residual(N) = fval; [sol,fval,exitflag,output] = solve(prob,x0,Options=optslsq,... ObjectiveDerivative='finite-differences',ConstraintDerivative='finite-differences'); lsqfd.Iterations(N) = output.iterations; lsqfd.Fcount(N) = output.funcCount; lsqfd.Residual(N) = fval; [sol,fval,exitflag,output] = solve(prob,x0,Options=optsfmincon,Solver="fmincon"); fmin.Iterations(N) = output.iterations; fmin.Fcount(N) = output.funcCount; fmin.Residual(N) = fval; [sol,fval,exitflag,output] = solve(prob,x0,Options=optsfmincon,Solver="fmincon",... ObjectiveDerivative='finite-differences',ConstraintDerivative='finite-differences'); fminfd.Iterations(N) = output.iterations; fminfd.Fcount(N) = output.funcCount; fminfd.Residual(N) = fval; end N = 1:50; plot(N,lsq.Iterations,'k',N,lsqfd.Iterations,'b--',N,fmin.Iterations,'g',N,fminfd.Iterations,'r--') legend('lsqnonlin','lsqnonlin FD','fmincon','fmincon FD','Location','northwest') xlabel('N') ylabel('Iterations') title('Iterations') figure semilogy(N,lsq.Fcount,'k',N,lsqfd.Fcount,'b--',N,fmin.Fcount,'g',N,fminfd.Fcount,'r--') legend('lsqnonlin','lsqnonlin FD','fmincon','fmincon FD','Location','northwest') xlabel('N') ylabel('log(Function count)') title('Function count, log-scaled') figure plot(N,lsq.Residual,'k',N,lsqfd.Residual,'b--',N,fmin.Residual,'g',N,fminfd.Residual,'r--') legend('lsqnonlin','lsqnonlin FD','fmincon','fmincon FD','Location','southeast') xlabel('N') ylabel('Residual') ylim([0,0.4]) title('Residual') end