优化代码生成基础知识
为 fmincon
生成代码
此示例说明如何为 fmincon
优化求解器生成代码。代码生成需要 MATLAB® Coder™ 许可证。有关代码生成要求的详细信息,请参阅 fmincon 背景中的代码生成。
该示例使用以下简单的目标函数。要在您自己的测试中使用此目标函数,请将代码复制到名为 rosenbrockwithgrad.m
的文件中。将此文件保存到您的 MATLAB 路径中。
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
要使用 rosenbrockwithgrad
目标函数生成代码,请创建一个名为 test_rosen.m
的文件,其中包含以下代码:
function [x,fval] = test_rosen opts = optimoptions('fmincon','Algorithm','sqp'); [x fval] = fmincon(@rosenbrockwithgrad,[-1,1],[],[],[],[],[-3,-3],[3,3],[],opts)
为 test_rosen
文件生成代码。
codegen -config:mex test_rosen
一段时间后,codegen
会创建一个名为 test_rosen_mex.mexw64
的 MEX 文件(文件扩展名因系统而异)。您可以通过输入 test_rosen_mex
来运行生成的 C 代码。结果如下或与以下内容类似:
x = 1.0000 1.0000 fval = 1.3346e-11 ans = 1.0000 1.0000
修改示例以提高效率
按照Optimization Code Generation for Real-Time Applications中的一些建议,设置生成代码的配置,以减少检查并使用静态内存分配。
cfg = coder.config('mex'); cfg.IntegrityChecks = false; cfg.SaturateOnIntegerOverflow = false; cfg.DynamicMemoryAllocation = 'Off';
将问题的边界从 [-3,3]
收紧到 [-2,2]
。此外,设置比默认值 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)
为 test_rosen2
文件生成代码。
codegen -config cfg test_rosen2
运行生成的代码。
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
此解几乎与之前的解一样好,其 fval
输出约为 2e-11
,而之前为 1e-11
。
尝试将允许的迭代次数限制为上一次计算所需迭代次数的一半。
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)
在 MATLAB 中运行 test_rosen3
。
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
在这种严格的迭代限制下,fmincon
不能得到良好解。准确性和速度之间的权衡难以把握。
为了保存函数计算并尽可能提高准确性,通过将 SpecifyObjectiveGradient
选项设置为 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)
使用与 test_rosen2
中相同的配置为 test_rosen4
生成代码。
codegen -config cfg test_rosen4
运行生成的代码。
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
与 test_rosen2
相比,迭代次数同为 40,但函数计算次数降低为 113
,而不是 155
。结果具有容差为 3e-20
的更好(更低)的目标函数值,而之前为 2e-11
。
另请参阅
fmincon
| codegen
(MATLAB Coder) | optimoptions