Main Content

优化代码生成基础知识

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

另请参阅

| (MATLAB Coder) |

相关主题