# Output Function for Problem-Based Optimization

This example shows how to use an output function to plot and store the history of the iterations for a nonlinear problem. This history includes the evaluated points, the search directions that the solver uses to generate points, and the objective function values at the evaluated points.

For the solver-based approach to this example, see Output Functions for Optimization Toolbox™.

Plot functions have the same syntax as output functions, so this example also applies to plot functions.

For both the solver-based approach and the problem-based approach, write the output function according to the solver-based approach. In the solver-based approach, you use a single vector variable, usually denoted `x`, instead of a collection of optimization variables of various sizes. So to write an output function for the problem-based approach, you must understand the correspondence between your optimization variables and the single solver-based `x`. To map between optimization variables and `x`, use `varindex`. In this example, to avoid confusion with an optimization variable named `x`, use "`in"` as the vector variable name.

### Problem Description

The problem is to minimize the following function of variables `x` and `y`:

`$f=\mathrm{exp}\left(x\right)\left(4{x}^{2}+2{y}^{2}+4xy+2y+1\right).$`

In addition, the problem has two nonlinear constraints:

`$\begin{array}{l}x+y-xy\ge 1.5\\ xy\ge -10.\end{array}$`

### Problem-Based Setup

To set up the problem in the problem-based approach, define optimization variables and an optimization problem object.

```x = optimvar('x'); y = optimvar('y'); prob = optimproblem;```

Define the objective function as an expression in the optimization variables.

`f = exp(x)*(4*x^2 + 2*y^2 + 4*x*y + 2*y + 1);`

Include the objective function in `prob`.

`prob.Objective = f;`

To include the nonlinear constraints, create optimization constraint expressions.

```cons1 = x + y - x*y >= 1.5; cons2 = x*y >= -10; prob.Constraints.cons1 = cons1; prob.Constraints.cons2 = cons2;```

Because this is a nonlinear problem, you must include an initial point structure `x0`. Use `x0.x = –1` and `x0.y = 1`.

```x0.x = -1; x0.y = 1;```

### Output Function

The `outfun` output function records a history of the points generated by `fmincon` during its iterations. The output function also plots the points and keeps a separate history of the search directions for the `sqp` algorithm. The search direction is a vector from the previous point to the next point that `fmincon` tries. During its final step, the output function saves the history in workspace variables, and saves a history of the objective function values at each iterative step.

For the required syntax of optimization output functions, see Output Function and Plot Function Syntax.

An output function takes a single vector variable as an input. But the current problem has two variables. To find the mapping between the optimization variables and the input variable, use `varindex`.

```idx = varindex(prob); idx.x```
```ans = 1 ```
`idx.y`
```ans = 2 ```

The mapping shows that `x` is variable 1 and `y` is variable 2. So, if the input variable is named `in`, then `x = in(1)` and `y = in(2)`.

`type outfun`
```function stop = outfun(in,optimValues,state,idx) persistent history searchdir fhistory stop = false; switch state case 'init' hold on history = []; fhistory = []; searchdir = []; case 'iter' % Concatenate current point and objective function % value with history. in must be a row vector. fhistory = [fhistory; optimValues.fval]; history = [history; in(:)']; % Ensure in is a row vector % Concatenate current search direction with % searchdir. searchdir = [searchdir;... optimValues.searchdirection(:)']; plot(in(idx.x),in(idx.y),'o'); % Label points with iteration number and add title. % Add .15 to idx.x to separate label from plotted 'o' text(in(idx.x)+.15,in(idx.y),... num2str(optimValues.iteration)); title('Sequence of Points Computed by fmincon'); case 'done' hold off assignin('base','optimhistory',history); assignin('base','searchdirhistory',searchdir); assignin('base','functionhistory',fhistory); otherwise end end ```

Include the output function in the optimization by setting the `OutputFcn` option. Also, set the `Algorithm` option to use the `'sqp'` algorithm instead of the default `'interior-point'` algorithm. Pass `idx` to the output function as an extra parameter in the last input. See Passing Extra Parameters.

```outputfn = @(in,optimValues,state)outfun(in,optimValues,state,idx); opts = optimoptions('fmincon','Algorithm','sqp','OutputFcn',outputfn);```

### Run Optimization Using Output Function

Run the optimization, including the output function, by using the '`Options'` name-value pair argument.

`[sol,fval,eflag,output] = solve(prob,x0,'Options',opts)`
```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: -9.5474 y: 1.0474 ```
```fval = 0.0236 ```
```eflag = OptimalSolution ```
```output = struct with fields: iterations: 10 funcCount: 22 algorithm: 'sqp' message: '...' constrviolation: 1.2434e-14 stepsize: 1.4785e-07 lssteplength: 1 firstorderopt: 7.1930e-10 bestfeasible: [1x1 struct] objectivederivative: "reverse-AD" constraintderivative: "closed-form" solver: 'fmincon' ```

Examine the iteration history. Each row of the `optimhistory` matrix represents one point. The last few points are very close, which explains why the plotted sequence shows overprinted numbers for points 8, 9, and 10.

`disp('Locations');disp(optimhistory)`
```Locations -1.0000 1.0000 -1.3679 1.2500 -1.6509 1.1813 -3.5870 2.0537 -4.4574 2.2895 -5.8015 1.5531 -7.6498 1.1225 -8.5223 1.0572 -9.5463 1.0464 -9.5474 1.0474 -9.5474 1.0474 ```

Examine the `searchdirhistory` and `functionhistory` arrays.

`disp('Search Directions');disp(searchdirhistory)`
```Search Directions 0 0 -0.3679 0.2500 -0.2831 -0.0687 -1.9360 0.8725 -0.8704 0.2358 -1.3441 -0.7364 -2.0877 -0.6493 -0.8725 -0.0653 -1.0241 -0.0108 -0.0011 0.0010 0.0000 -0.0000 ```
`disp('Function Values');disp(functionhistory)`
```Function Values 1.8394 1.8513 1.7757 0.9839 0.6343 0.3250 0.0978 0.0517 0.0236 0.0236 0.0236 ```

### Unsupported Functions Require `fcn2optimexpr`

If your objective function or nonlinear constraint functions are not composed of elementary functions, you must convert the functions to optimization expressions using `fcn2optimexpr`. See Convert Nonlinear Function to Optimization Expression. For this example, you would enter the following code:

```fun = @(x,y)exp(x)*(4*x^2 + 2*y^2 + 4*x*y + 2*y + 1); f = fcn2optimexpr(fun,x,y);```

For the list of supported functions, see Supported Operations for Optimization Variables and Expressions.