www.gusucode.com > optim 案例源码 matlab代码程序 > optim/OptimizeANonsmoothFunctionExample.m

    %% Optimize a Nonsmooth Function
% This example shows the importance of choosing an appropriate solver. It
% also shows that a single point of non-smoothness can cause failures in
% Optimization Toolbox(TM) solvers, and that appropriate option choices can
% alleviate these failures.
%% A Function with a Single Nonsmooth Point
% The function $f(x) = \sqrt{||x||}$ is nonsmooth only at the
% point 0, which is the minimizing point:
figure
fsurf(@(x,y)(x.^2 + y.^2).^(1/4))
%% Minimize Using |fminsearch|
% Start |fminsearch| from a nonzero six-dimensional point and attempt to
% locate the minimum of $f$. The documentation states that |fminsearch|
% sometimes can handle discontinuities, so this is a reasonable first try.
fun = @(x)sqrt(norm(x));
x0 = [1,2;3,4;5,6];
rng default
x0 = x0 + rand(size(x0))

[xfms,fvalfms,eflagfms,outputfms] = fminsearch(fun,x0)
%%
% |fminsearch| did not substantially improve the initial point, and took
% hundreds of function evaluations.
%% Use |patternsearch|
% |patternsearch| is the recommended first solver to try for nonsmooth
% problems. See <docid:gads.bsa_e9p>.
[xps,fvalps,eflagps,outputps] = patternsearch(fun,x0)
%%
% |patternsearch| reached a good solution, but took about 2,000 function
% evaluations to do so.
%% Use |particleswarm|
% |particleswarm| is recommended as the next solver to try. See
% <docid:gads.bu9r6hl-6>.
[xpsw,fvalpsw,eflagpsw,outputpsw] = particleswarm(fun,6)
%%
% |particleswarm| found an accurate solution, but took over 15,000 function
% evaluations.
%% Use |ga|
% |ga| is a popular solver, but is not recommended as the first solver to
% try. See how well it works on this problem.
[xga,fvalga,eflagga,outputga] = ga(fun,6)
%%
% |ga| did not find as good a solution as |patternsearch| or
% |particleswarm|, and took over 50,000 function evaluations.
%% Use Optimization Toolbox Solvers
% |fminunc| does not produce an accurate solution, though it does halt
% after relatively few function evaluations.
options = optimoptions('fminunc','Algorithm','quasi-newton');
[xfmu,fvalfmu,eflagfmu,outputfmu] = fminunc(fun,x0,options)
%%
% However, |fmincon| with default options produces an accurate solution
% with fewer than 500 function evaluations.
[xfmc,fvalfmc,eflagfmc,outputfmc] = fmincon(fun,x0)
%% Use Symbolic Gradients and Hessian for Better, Faster Results
% If you have Symbolic Math Toolbox(TM), you can improve the preformance
% and robustness of Optimization Toolbox solvers.
%
% Compute the gradients and Hessian of the objective function symbolically,
% and use |matlabFunction| to turn the symbolic calculation into a function
% handle. For more examples of this method of obtaining derivatives for the
% objective function, see <docid:optim_ug.brv_i_1> or
% <docid:optim_examples.example-ex44573088>.
x = sym('x%d%d',[3,2],'real');
y = norm(x(:))^(1/2);
jy = jacobian(y,x(:)).';
hy = jacobian(jy,x(:));
spikefun = matlabFunction(y,jy,hy,'vars',{x});
%%
% Use |spikefun| as the objective function for |fminunc|, along with
% options to use the associated gradient and Hessian.
options = optimoptions('fminunc','Algorithm','trust-region',...
'SpecifyObjectiveGradient',true,'HessianFcn','objective');
[xfmu2,fvalfmu2,eflagfmu2,outputfmu2] = fminunc(spikefun,x0,options)
%%
% This time, |fminunc| solved the problem accurately, and with only 30
% function evaluations.
%% Summary of Results
% Choosing the appropriate solver and options leads to better, faster
% results. This summary shows how variable results can be.
disp('Solver            Solution quality    Number of Function Evaluations')
disp(['fminsearch           Bad               ',num2str(outputfms.funcCount)])
disp(['patternsearch        Good              ',num2str(outputps.funccount)])
disp(['particleswarm        Good              ',num2str(outputpsw.funccount)])
disp(['ga                   Mediocre          ',num2str(outputga.funccount)])
disp(['fminunc              Mediocre          ',num2str(outputfmu.funcCount)])
disp(['fmincon              Good              ',num2str(outputfmc.funcCount)])
disp(['fminunc+derivatives  Good              ',num2str(outputfmu2.funcCount)])