Main Content

Generación de código para conceptos básicos de optimización

Generar código para fmincon

Este ejemplo muestra cómo generar código para el solver de optimización fmincon. La generación de código requiere una licencia de MATLAB® Coder™. Para obtener detalles de los requisitos de la generación de código, consulte Generación de código en segundo plano de fmincon.

El ejemplo utiliza la siguiente función objetivo simple. Para utilizar esta función objetivo en su propia prueba, copie el código en un archivo llamado rosenbrockwithgrad.m. Guarde el archivo en su ruta de 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

Para generar código utilizando la función objetivo rosenbrockwithgrad, cree un archivo llamado test_rosen.m que contenga este código:

function [x,fval] = test_rosen
opts = optimoptions('fmincon','Algorithm','sqp');
[x fval] = fmincon(@rosenbrockwithgrad,[-1,1],[],[],[],[],[-3,-3],[3,3],[],opts)

Genere código para el archivo test_rosen.

codegen -config:mex test_rosen

Pasado un tiempo, codegen crea un archivo MEX llamado test_rosen_mex.mexw64 (la extensión de archivo variará en función del sistema). Puede ejecutar el código C resultante introduciendo test_rosen_mex. Los resultados son los siguientes o similares:

x =

    1.0000    1.0000


fval =

   1.3346e-11


ans =

    1.0000    1.0000

Modificar un ejemplo por eficiencia

Siguiendo algunas de las sugerencias de Optimization Code Generation for Real-Time Applications, ajuste la configuración del código generado para que tenga menos comprobaciones y para que use la asignación de memoria estática.

cfg = coder.config('mex');
cfg.IntegrityChecks = false;
cfg.SaturateOnIntegerOverflow = false;
cfg.DynamicMemoryAllocation = 'Off';

Ajuste los límites del problema de [-3,3] a [-2,2]. Asimismo, establezca una tolerancia de optimalidad más flexible que la predeterminada 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)

Genere código para el archivo test_rosen2.

codegen -config cfg test_rosen2

Ejecute el código resultante.

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

Esta solución es casi tan buena como la solución anterior, con la salida fval alrededor de 2e-11 en comparación con el valor 1e-11 anterior.

Intente limitar el número de iteraciones permitidas a la mitad de las realizadas en el cálculo anterior.

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)

Ejecute test_rosen3 en 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

Con este nivel de iteración estricto, fmincon no alcanza una buena solución. El equilibrio entre precisión y velocidad puede ser difícil de gestionar.

Para ahorrar evaluaciones de función y posiblemente mejorar la precisión, utilice las derivadas integradas del ejemplo estableciendo la opción SpecifyObjectiveGradient en 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)

Genere código para test_rosen4 utilizando la misma configuración que en test_rosen2.

codegen -config cfg test_rosen4

Ejecute el código resultante.

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

En comparación con test_rosen2, el número de iteraciones es el mismo con 40, pero el número de evaluaciones de función es menor con 113 en lugar de 155. El resultado tiene un valor mejor (más bajo) de la función objetivo de 3e-20 en comparación con 2e-11.

Consulte también

| (MATLAB Coder) |

Temas relacionados