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 code that
calls rosenbrockwithgrad. You must set options to use the
"sqp" algorithm. Also, set the
UseCodegenSolver option to true so you can
verify the results in MATLAB using the same code as is generated.
function [x,fval] = test_rosen opts = optimoptions("fmincon",... Algorithm="sqp",UseCodegenSolver=true); [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.0000Modify 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",UseCodegenSolver=true,... 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.0000This 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",UseCodegenSolver=true,... 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.0716With 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",UseCodegenSolver=true,... 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.0000Compared 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