Main Content

Output Functions for GlobalSearch and MultiStart

What Are Output Functions?

Output functions allow you to examine intermediate results in an optimization. Additionally, they allow you to halt a solver programmatically.

There are two types of output functions, like the two types of output structures:

  • Global output functions run after each local solver run. They also run when the global solver starts and ends.

  • Local output functions run after each iteration of a local solver. See Output Functions for Optimization Toolbox.

To use global output functions:

  • Write output functions using the syntax described in OutputFcn.

  • Set the OutputFcn property of your GlobalSearch or MultiStart solver to the function handle of your output function. You can use multiple output functions by setting the OutputFcn property to a cell array of function handles.

The built-in @savelocalsolutions output function saves all local solutions to the localSolTable variable in the base workspace. This output function saves the infeasible local solutions as well as the feasible local solutions; the solutions output of run returns only the local solutions with positive exit flag.

Collect All Local Solutions

This example shows how to use the savelocalsolutions output function with MultiStart to collect all the local solutions found during a run. Begin by specifying savelocalsolutions as an output function for MultiStart.

ms = MultiStart(OutputFcn=@savelocalsolutions);

Create a problem in three variables for MultiStart using the bigtoleft objective function and the twocone nonlinear constraint function, listed in Helper Functions at the end of this example. Set lower bounds of –1e5 in each component and upper bounds of 1e5. For details of this objective function and nonlinear constraint function, see fmincon Interior-Point Algorithm with Analytic Hessian.

fun = @bigtoleft;
lb = -1e5*ones(1,3);
ub = -lb;

The objective and constraint functions contain derivative information. Set the options to use derivatives.

opts = optimoptions(@fmincon,SpecifyObjectiveGradient=true,...
    SpecifyConstraintGradient=true);

Set the initial point to [–10,–10,–10] and create the optimization problem.

x0 = -10*ones(1,3);
prob = createOptimProblem("fmincon",x0=x0,...
    lb = lb,ub = ub,...
    objective=fun,nonlcon=@twocone,options=opts);

For reproducibility, set the random seed. Run MultiStart on 35 start points.

rng default
[x,fval,eflag,output,solns] = run(ms,prob,35)
MultiStart completed some of the runs from the start points. 

11 out of 35 local solver runs converged with a positive local solver exitflag.

x =

   -6.5000   -0.0000   -3.5000


fval =

  -2.8941e+03


eflag =

     2


output = 

  struct with fields:

                funcCount: 73904
         localSolverTotal: 35
       localSolverSuccess: 11
    localSolverIncomplete: 23
    localSolverNoSolution: 1
                  message: 'MultiStart completed some of the runs from the start points. ↵↵11 out of 35 local solver runs converged with a positive local solver exitflag.'


solns = 

  1×2 GlobalOptimSolution array with properties:

    X
    Fval
    Exitflag
    Output
    X0

The workspace contains the localSolTable variable, which has all 35 local solutions. In contrast, the output structure shows that only 11 local solver runs were successful.

size(localSolTable)
ans =

    35     4

To see the kind of information returned by the output function, view the first line of localSolTable.

disp(localSolTable(1,:))
                   X                     fval      exitflag    constrviolation
    ________________________________    _______    ________    _______________

    -6.5    2.3432e-07          -3.5    -2894.1       1               0       

The output function returns the local solution X, its associated objective function value fval, the exit flag corresponding to that local solver run, and the constraint violation, which is 0 for no constraint violations.

Helper Functions

This code creates the bigtoleft helper function.

function [f,gradf] = bigtoleft(x)
% This is a simple function that grows rapidly negative
% as x(1) becomes negative
%
f = 10*x(:,1).^3+x(:,1).*x(:,2).^2+x(:,3).*(x(:,1).^2+x(:,2).^2);

if nargout > 1

   gradf=[30*x(1)^2+x(2)^2+2*x(3)*x(1);
       2*x(1)*x(2)+2*x(3)*x(2);
       (x(1)^2+x(2)^2)];

end
end

This code creates the twocone helper function.

function [c,ceq,gradc,gradceq] = twocone(x)
% This constraint is two cones, z > -10 + r
% and z < 3 - r

ceq = [];
r = sqrt(x(1)^2 + x(2)^2);
c = [-10+r-x(3);
    x(3)-3+r];

if nargout > 2

    gradceq = [];
    gradc = [x(1)/r,x(1)/r;
       x(2)/r,x(2)/r;
       -1,1];

end
end

Custom GlobalSearch Output Function

This output function stops GlobalSearch after it finds five distinct local minima with positive exit flags, or after it finds a local minimum value less than 0.5. The output function uses a persistent local variable, foundLocal, to store the local results. foundLocal enables the output function to determine whether a local solution is distinct from others, to within a tolerance of 1e-4.

To store local results using nested functions instead of persistent variables, see Example of a Nested Output Function.

  1. Write the output function using the syntax described in OutputFcn.

    function stop = StopAfterFive(optimValues, state)
    persistent foundLocal
    stop = false;
    switch state
        case 'init'
            foundLocal = []; % initialized as empty
        case 'iter'
            newf = optimValues.localsolution.Fval;
            exitflag = optimValues.localsolution.Exitflag;
            % Now check if the exit flag is positive and
            % the new value differs from all others by at least 1e-4
            % If so, add the new value to the newf list
            if exitflag > 0 && all(abs(newf - foundLocal) > 1e-4)
                foundLocal = [foundLocal;newf];
                % Now check if the latest value added to foundLocal
                % is less than 1/2
                % Also check if there are 5 local minima in foundLocal
                % If so, then stop
                if foundLocal(end) < 0.5 || length(foundLocal) >= 5
                    stop = true;
                end
            end
    end
  2. Save StopAfterFive.m as a file in a folder on your MATLAB® path.

  3. Write the objective function and create an optimization problem structure as in Find Global or Multiple Local Minima.

    function f = sawtoothxy(x,y)
    [t r] = cart2pol(x,y); % change to polar coordinates
    h = cos(2*t - 1/2)/2 + cos(t) + 2;
    g = (sin(r) - sin(2*r)/2 + sin(3*r)/3 - sin(4*r)/4 + 4) ...
        .*r.^2./(r+1);
    f = g.*h;
    end
  4. Save sawtoothxy.m as a file in a folder on your MATLAB path.

  5. At the command line, create the problem structure:

    problem = createOptimProblem('fmincon',...
        'objective',@(x)sawtoothxy(x(1),x(2)),...
        'x0',[100,-50],'options',...
        optimoptions(@fmincon,'Algorithm','sqp'));
  6. Create a GlobalSearch object with @StopAfterFive as the output function, and set the iterative display property to 'iter'.

    gs = GlobalSearch('OutputFcn',@StopAfterFive,'Display','iter');
  7. (Optional) To get the same answer as this example, set the default random number stream.

    rng default
  8. Run the problem.

    [x,fval] = run(gs,problem)
     Num Pts                 Best       Current    Threshold        Local        Local                 
    Analyzed  F-count        f(x)       Penalty      Penalty         f(x)     exitflag        Procedure
           0      200       555.5                                   555.5            0    Initial Point
         200     1463   1.547e-15                               1.547e-15            1    Stage 1 Local
    
    GlobalSearch stopped by the output or plot function.
    
    1 out of 2 local solver runs converged with a positive local solver exit flag.
    
    x =
    
       1.0e-07 *
    
        0.0414    0.1298
    
    
    fval =
    
       1.5467e-15

The run stopped early because GlobalSearch found a point with a function value less than 0.5.

No Parallel Output Functions

While MultiStart can run in parallel, it does not support global output functions and plot functions in parallel. Furthermore, while local output functions and plot functions run on workers when MultiStart runs in parallel, the effect differs from running serially. Local output and plot functions do not create a display when running on workers. You do not see any other effects of output and plot functions until the worker passes its results to the client (the originator of the MultiStart parallel jobs).

For information on running MultiStart in parallel, see Parallel Computing.

Related Topics