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 .
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.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',... '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',... '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',... '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
| codegen (matlab coder) |