Code Generation for Optimization Basics
Generate Code for fmincon
This example shows how to generate code for the fmincon
optimization solver. Code generation requires a MATLAB®
Coder™ license. For details of code generation requirements, see Code Generation in fmincon Background.
The example uses the following simple objective function. To use this objective
function in your own testing, copy the code to a file named
rosenbrockwithgrad.m
. Save the file on your MATLAB path.
function [f,g] = rosenbrockwithgrad(x) % Calculate objective f f = 100*(x(2) - x(1)^2)^2 + (1 - x(1))^2; if nargout > 1 % gradient required g = [-400*(x(2) - x(1)^2)*x(1) - 2*(1 - x(1)); 200*(x(2) - x(1)^2)]; end
To generate code using the rosenbrockwithgrad
objective
function, create a file named test_rosen.m
containing this
code:
function [x,fval] = test_rosen opts = optimoptions('fmincon','Algorithm','sqp'); [x fval] = fmincon(@rosenbrockwithgrad,[-1,1],[],[],[],[],[-3,-3],[3,3],[],opts)
Generate code for the test_rosen
file.
codegen -config:mex test_rosen
After some time, codegen
creates a MEX file named
test_rosen_mex.mexw64
(the file extension will vary,
depending on your system). You can run the resulting C code by entering
test_rosen_mex
. The results are the following or
similar:
x = 1.0000 1.0000 fval = 1.3346e-11 ans = 1.0000 1.0000
Modify Example for Efficiency
Following some of the suggestions in Optimization Code Generation for Real-Time Applications, set the configuration of the generated code to have fewer checks and to use static memory allocation.
cfg = coder.config('mex'); cfg.IntegrityChecks = false; cfg.SaturateOnIntegerOverflow = false; cfg.DynamicMemoryAllocation = 'Off';
Tighten the bounds on the problem from [-3,3]
to
[-2,2]
. Also, set a looser optimality tolerance than the
default 1e-6
.
function [x,fval] = test_rosen2 opts = optimoptions('fmincon','Algorithm','sqp',... 'OptimalityTolerance',1e-5); [x fval eflag output] = fmincon(@rosenbrockwithgrad,[-1,1],[],[],[],[],... [-2,-2],[2,2],[],opts)
Generate code for the test_rosen2
file.
codegen -config cfg test_rosen2
Run the resulting code.
test_rosen2_mex
x = 1.0000 1.0000 fval = 2.0057e-11 eflag = 2 output = struct with fields: iterations: 40 funcCount: 155 algorithm: 'sqp' constrviolation: 0 stepsize: 5.9344e-08 lssteplength: 1 ans = 1.0000 1.0000
This solution is almost as good as the previous solution, with the
fval
output around 2e-11
compared to the
previous 1e-11
.
Try limiting the number of allowed iterations to half of those taken in the previous computation.
function [x,fval] = test_rosen3 options = optimoptions('fmincon','Algorithm','sqp',... 'MaxIterations',20); [x fval eflag output] = fmincon(@rosenbrockwithgrad,[-1,1],[],[],[],[],... [-2,-2],[2,2],[],options)
Run test_rosen3
in MATLAB.
test_rosen3
x = 0.2852 0.0716 fval = 0.5204 eflag = 0 output = struct with fields: iterations: 20 funcCount: 91 algorithm: 'sqp' message: '↵Solver stopped prematurely.↵↵fmincon stopped because it exceeded the iteration limit,↵options.MaxIterations = 2.000000e+01.↵↵' constrviolation: 0 stepsize: 0.0225 lssteplength: 1 firstorderopt: 1.9504 ans = 0.2852 0.0716
With this severe iteration limit, fmincon
does not reach a
good solution. The tradeoff between accuracy and speed can be difficult to
manage.
To save function evaluations and possibly increase accuracy, use the built-in
derivatives of the example by setting the
SpecifyObjectiveGradient
option to
true
.
function [x,fval] = test_rosen4 options = optimoptions('fmincon','Algorithm','sqp',... 'SpecifyObjectiveGradient',true); [x fval eflag output] = fmincon(@rosenbrockwithgrad,[-1,1],[],[],[],[],... [-2,-2],[2,2],[],options)
Generate code for test_rosen4
using the same configuration as
in test_rosen2
.
codegen -config cfg test_rosen4
Run the resulting code.
test_rosen4_mex
x = 1.0000 1.0000 fval = 3.3610e-20 eflag = 2 output = struct with fields: iterations: 40 funcCount: 113 algorithm: 'sqp' constrviolation: 0 stepsize: 9.6356e-08 lssteplength: 1 ans = 1.0000 1.0000
Compared to test_rosen2
, the number of iterations is the same
at 40, but the number of function evaluations is lower at 113
instead of 155
. The result has a better (lower) objective
function value of 3e-20
compared to
2e-11
.
See Also
fmincon
| codegen
(MATLAB Coder) | optimoptions