## 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.