Main Content

Escribir funciones objetivo escalares

Archivos de función

Un archivo de función objetivo escalar acepta una entrada, por ejemplo x, y devuelve una salida escalar real, por ejemplo f. La entrada x puede ser un escalar, vector o matriz. Un archivo de función puede devolver más salidas (consulte Incluir gradientes y matrices hessianas).

Por ejemplo, suponga que su objetivo es una función de tres variables, x, y y z:

f(x) = 3*(xy)4 + 4*(x + z)2 / (1 + x2 + y2 + z2) + cosh(x – 1) + tanh(y + z).

  1. Escriba esta función como un archivo que acepta el vector xin = [x;y;z] y devuelve f:

    function f = myObjective(xin)
    f = 3*(xin(1)-xin(2))^4 + 4*(xin(1)+xin(3))^2/(1+norm(xin)^2) ...
        + cosh(xin(1)-1) + tanh(xin(2)+xin(3));
  2. Guárdelo como un archivo llamado myObjective.m en una carpeta de la ruta de MATLAB®.

  3. Compruebe que la función realice la evaluación correctamente:

    myObjective([1;2;3])
    
    ans =
        9.2666

Para obtener más información sobre cómo incluir parámetros adicionales, consulte Pasar parámetros adicionales. Para ver más ejemplos complejos de archivos de función, consulte Minimization with Gradient and Hessian Sparsity Pattern o Minimization with Bound Constraints and Banded Preconditioner.

Funciones locales y funciones anidadas

Las funciones pueden existir dentro de otros archivos como funciones locales o funciones anidadas. Con las funciones locales o funciones anidadas se puede reducir el número de archivos diferentes que se guardan. Con las funciones anidadas también podrá acceder a parámetros adicionales, como se muestra en Funciones anidadas.

Por ejemplo, suponga que desea minimizar la función objetivo myObjective.m, descrita en Archivos de función, sujeta a la restricción ellipseparabola.m, descrita en Restricciones no lineales. En lugar de escribir dos archivos, myObjective.m y ellipseparabola.m, escriba un archivo que contenga ambas funciones como funciones locales:

function [x fval] = callObjConstr(x0,options)
% Using a local function for just one file

if nargin < 2
    options = optimoptions('fmincon','Algorithm','interior-point');
end

[x fval] = fmincon(@myObjective,x0,[],[],[],[],[],[], ...
    @ellipseparabola,options);

function f = myObjective(xin)
f = 3*(xin(1)-xin(2))^4 + 4*(xin(1)+xin(3))^2/(1+sum(xin.^2)) ...
    + cosh(xin(1)-1) + tanh(xin(2)+xin(3));

function [c,ceq] = ellipseparabola(x)
c(1) = (x(1)^2)/9 + (x(2)^2)/4 - 1;
c(2) = x(1)^2 - x(2) - 1;
ceq = [];

Resuelva la minimización restringida comenzando por el punto [1;1;1]:

[x fval] = callObjConstr(ones(3,1))

Local minimum found that satisfies the constraints.

Optimization completed because the objective function is 
non-decreasing in feasible directions, to within the default 
value of the function tolerance, and constraints are satisfied 
to within the default value of the constraint tolerance.

x =
    1.1835
    0.8345
   -1.6439

fval =
    0.5383

Objetivos de función anónima

Utilice funciones anónimas para escribir funciones objetivo simples. Para obtener más información sobre funciones anónimas, consulte ¿Qué son las funciones anónimas?. La función de Rosenbrock es lo suficientemente simple como para escribirla como una función anónima:

anonrosen = @(x)(100*(x(2) - x(1)^2)^2 + (1-x(1))^2);
Compruebe que anonrosen realice la evaluación correctamente en [-1 2]:
anonrosen([-1 2])

ans =
   104
Minimizando anonrosen con fminunc, se obtienen los siguientes resultados:
options = optimoptions(@fminunc,'Algorithm','quasi-newton');
[x fval] = fminunc(anonrosen,[-1;2],options)

Local minimum found.

Optimization completed because the size of the gradient
is less than the default value of the function tolerance.

x =
    1.0000
    1.0000

fval =
  1.2266e-10

Incluir gradientes y matrices hessianas

Proporcionar derivadas para solvers

Para fmincon y fminunc, puede incluir gradientes en la función objetivo. Por lo general, los solvers son más robustos y pueden ser ligeramente más rápidos cuando se incluyen gradientes. Consulte Beneficios de incluir derivadas. Para incluir también segundas derivadas (matrices hessianas), consulte Incluir matrices hessianas.

La siguiente tabla muestra qué algoritmos pueden utilizar gradientes y matrices hessianas.

SolverAlgoritmoGradienteMatriz hessiana
fminconactive-setOpcionalNo
interior-pointOpcionalOpcional (consulte Matriz hessiana para el algoritmo fmincon interior-point)
sqpOpcionalNo
trust-region-reflectiveNecesarioOpcional (consulte Matriz hessiana para los algoritmos fminunc trust-region o fmincon trust-region-reflective)
fminuncquasi-newtonOpcionalNo
trust-regionNecesarioOpcional (consulte Matriz hessiana para los algoritmos fminunc trust-region o fmincon trust-region-reflective)

Cómo incluir gradientes

  1. Escriba código que devuelva:

    • La función objetivo (escalar) como primera salida

    • El gradiente (vector) como segunda salida

  2. Establezca la opción SpecifyObjectiveGradient en true mediante optimoptions. Si fuera apropiado, establezca también la opción SpecifyConstraintGradient en true.

  3. Opcionalmente, compruebe que la función de gradiente coincida con una aproximación de diferencias finitas. Consulte Checking Validity of Gradients or Jacobians.

Sugerencia

Para una mayor flexibilidad, escriba código condicionalizado. Condicionalizado significa que el número de salidas de función puede variar, como se muestra en el siguiente ejemplo. El código condicionalizado no provoca un error en función del valor de la opción SpecifyObjectiveGradient. El código no condicionalizado requiere que establezca las opciones correctamente.

Por ejemplo, considere la función de Rosenbrock

f(x)=100(x2x12)2+(1x1)2,

que se describe y representa en Resolver un problema no lineal restringido basado en solvers. El gradiente de f(x) es

f(x)=[400(x2x12)x12(1x1)200(x2x12)],

rosentwo es una función condicionalizada que devuelve lo que el solver necesite:

function [f,g] = rosentwo(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

nargout comprueba el número de argumentos que especifica una función que realiza la llamada. Consulte Buscar el número de argumentos de funciones.

El solver fminunc, diseñado para optimización no restringida, permite minimizar la función de Rosenbrock. Indique a fminunc que utilice el gradiente y la matriz hessiana estableciendo options:

options = optimoptions(@fminunc,'Algorithm','trust-region',...
    'SpecifyObjectiveGradient',true);

Ejecute fminunc comenzando en [-1;2]:

[x fval] = fminunc(@rosentwo,[-1;2],options)
Local minimum found.

Optimization completed because the size of the gradient
is less than the default value of the function tolerance.

x =
    1.0000
    1.0000

fval =
  1.9886e-17

Si tiene una licencia de Symbolic Math Toolbox™, puede calcular gradientes y matrices hessianas de forma automática, tal y como se describe en Calculate Gradients and Hessians Using Symbolic Math Toolbox.

Incluir matrices hessianas

Puede incluir segundas derivadas con los algoritmos fmincon 'trust-region-reflective' e 'interior-point', y con el algoritmo fminunc 'trust-region'. Hay varias formas de incluir información de matrices hessianas, en función del tipo de información y del algoritmo.

También debe incluir gradientes (establezca SpecifyObjectiveGradient en true y, si procede, SpecifyConstraintGradient en true) para incluir matrices hessianas.

Matriz hessiana para los algoritmos fminunc trust-region o fmincon trust-region-reflective.  Estos algoritmos o bien no tienen restricciones, o bien tienen únicamente límites de restricciones o restricciones de igualdad lineales. De este modo, la matriz hessiana es la matriz de segundas derivadas de la función objetivo.

Incluya la matriz hessiana como tercera salida de la función objetivo. Por ejemplo, la matriz hessiana H(x) de la función de Rosenbrock es (consulte Cómo incluir gradientes)

H(x)=[1200x12400x2+2400x1400x1200].

Incluya esta matriz hessiana en el objetivo:

function [f, g, H] = rosenboth(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)];
    
    if nargout > 2 % Hessian required
        H = [1200*x(1)^2-400*x(2)+2, -400*x(1);
            -400*x(1), 200];  
    end

end

Establezca HessianFcn en 'objective'. Por ejemplo:

options = optimoptions('fminunc','Algorithm','trust-region',...
    'SpecifyObjectiveGradient',true,'HessianFcn','objective');

Matriz hessiana para el algoritmo fmincon interior-point.  La matriz hessiana es la matriz hessiana del lagrangiano, donde el lagrangiano L(x,λ) es

L(x,λ)=f(x)+λg,igi(x)+λh,ihi(x).

g y h son funciones vectoriales que representan todas las restricciones de desigualdad e igualdad respectivamente (es decir, límites de restricciones y restricciones lineales y no lineales), por lo que el problema de minimización es

minxf(x) subject to g(x)0, h(x)=0.

Para obtener más detalles, consulte Teoría de optimalidad restringida. La matriz hessiana del lagrangiano es

xx2L(x,λ)=2f(x)+λg,i2gi(x)+λh,i2hi(x).(1)

Para incluir una matriz hessiana, escriba una función con la sintaxis

hessian = hessianfcn(x,lambda)

hessian es una matriz de n por n, dispersa o densa, donde n es el número de variables. Si hessian es grande y tiene relativamente pocas entradas distintas de cero, ahorre tiempo de ejecución y memoria representando hessian como una matriz dispersa. lambda es una estructura con los vectores de multiplicadores de Lagrange asociados a las restricciones no lineales:

lambda.ineqnonlin
lambda.eqnonlin

fmincon calcula la estructura lambda y la pasa a su función de matriz hessiana. hessianfcn debe calcular las sumas en Ecuación 1. Indique que va a proporcionar una matriz hessiana estableciendo estas opciones:

options = optimoptions('fmincon','Algorithm','interior-point',...
    'SpecifyObjectiveGradient',true,'SpecifyConstraintGradient',true,...
    'HessianFcn',@hessianfcn);

Por ejemplo, para incluir una matriz hessiana para la función de Rosenbrock restringida al disco unidad x12+x221, observe que la función de restricción g(x)=x12+x2210 tiene gradiente y matriz de segunda derivada

g(x)=[2x12x2]Hg(x)=[2002].

Escriba la función de matriz hessiana como

function Hout = hessianfcn(x,lambda)
% Hessian of objective
H = [1200*x(1)^2-400*x(2)+2, -400*x(1);
            -400*x(1), 200];
% Hessian of nonlinear inequality constraint
Hg = 2*eye(2);
Hout = H + lambda.ineqnonlin*Hg;

Guarde hessianfcn en la ruta de MATLAB. Para completar el ejemplo, la función de restricción incluyendo gradientes es

function [c,ceq,gc,gceq] = unitdisk2(x)
c = x(1)^2 + x(2)^2 - 1;
ceq = [ ];

if nargout > 2
    gc = [2*x(1);2*x(2)];
    gceq = [];
end

Resuelva el problema incluyendo gradientes y una matriz hessiana.

fun = @rosenboth;
nonlcon = @unitdisk2;
x0 = [-1;2];
options = optimoptions('fmincon','Algorithm','interior-point',...
    'SpecifyObjectiveGradient',true,'SpecifyConstraintGradient',true,...
    'HessianFcn',@hessianfcn);
[x,fval,exitflag,output] = fmincon(fun,x0,[],[],[],[],[],[],@unitdisk2,options);

Para ver otros ejemplos utilizando una matriz hessiana interior-point, consulte Algoritmo interior-point de fmincon con matriz hessiana analítica y Calculate Gradients and Hessians Using Symbolic Math Toolbox.

Función de multiplicación de matriz hessiana.  En lugar de una función de matriz hessiana completa, los algoritmos fminconinterior-point y trust-region-reflective permiten proporcionar una función de multiplicación de matriz hessiana. Esta función da el resultado de un producto del vector por la matriz hessiana sin calcular la matriz hessiana directamente. Esto puede ahorrar memoria. La opción SubproblemAlgorithm debe ser 'cg' para que una función de multiplicación de matriz hessiana funcione; este es el trust-region-reflective predeterminado.

Las sintaxis para los dos algoritmos difieren.

  • Para el algoritmo interior-point, la sintaxis es

    W = HessMultFcn(x,lambda,v);

    El resultado W debería ser el producto de H*v, donde H es la matriz hessiana del lagrangiano en x (consulte Ecuación 1), lambda es el multiplicador de Lagrange (calculado por fmincon) y v es un vector de tamaño n por 1. Establezca las opciones de la siguiente manera:

    options = optimoptions('fmincon','Algorithm','interior-point','SpecifyObjectiveGradient',true,... 
        'SpecifyConstraintGradient',true,'SubproblemAlgorithm','cg','HessianMultiplyFcn',@HessMultFcn);

    Proporcione la función HessMultFcn, que devuelve un vector de n por 1, donde n es el número de dimensiones de x. La opción HessianMultiplyFcn permite pasar el resultado de multiplicar la matriz hessiana por un vector sin calcular dicha matriz hessiana.

  • El algoritmo trust-region-reflective no incluye a lambda:

    W = HessMultFcn(H,v);

    El resultado W = H*v. fmincon pasa H como el valor devuelto en la tercera salida de la función objetivo (consulte Matriz hessiana para los algoritmos fminunc trust-region o fmincon trust-region-reflective). fmincon también pasa v, un vector o matriz con n filas. El número de columnas de v puede variar, así que escriba HessMultFcn para aceptar un número arbitrario de columnas. H no tiene por qué ser la matriz hessiana; es más, puede ser cualquier elemento que permita calcular W = H*v.

    Establezca las opciones de la siguiente manera:

    options = optimoptions('fmincon','Algorithm','trust-region-reflective',... 
        'SpecifyObjectiveGradient',true,'HessianMultiplyFcn',@HessMultFcn);

    Para ver un ejemplo que utilice una función de multiplicación de matriz hessiana con el algoritmo trust-region-reflective, consulte Minimization with Dense Structured Hessian, Linear Equalities.

Beneficios de incluir derivadas

Si no proporciona gradientes, los solvers estiman gradientes mediante diferencias finitas. Si proporciona gradientes, el solver no necesita realizar esta estimación de diferencias finitas, por lo que puede ahorrar tiempo y obtener más precisión, aunque una estimación de diferencias finitas puede ser más rápida para derivadas complicadas. Además, los solvers utilizan una matriz hessiana aproximada, que puede diferir bastante de la matriz hessiana real. Proporcionando una matriz hessiana, se puede obtener una solución en menos iteraciones. Por ejemplo, consulte el final de Calculate Gradients and Hessians Using Symbolic Math Toolbox.

Para problemas restringidos, proporcionar un gradiente ofrece otra ventaja. Un solver puede alcanzar un punto x de forma que x sea factible, pero, para este punto x, las diferencias finitas alrededor de x siempre conducen a un punto no factible. Suponga, además, que la función objetivo en un punto no factible devuelve una salida compleja, Inf, NaN o un error. En este caso, un solver puede fallar o detenerse prematuramente. Proporcionar un gradiente permite al solver continuar. Para aprovechar esta ventaja, es posible que también necesite incluir el gradiente de una función de restricción no lineal y establecer la opción SpecifyConstraintGradient en true. Consulte Restricciones no lineales.

Escoger una aproximación de matriz hessiana de entrada para fmincon interior-point

El algoritmo fmincon interior-point cuenta con muchas opciones para seleccionar una aproximación de matriz hessiana de entrada. Para obtener más detalles de la sintaxis, consulte Matriz hessiana como entrada. Aquí están las opciones, junto con las estimaciones de sus características relativas.

Matriz hessianaUso relativo de memoriaEficiencia relativa
'bfgs' (valor predeterminado)Alto (para problemas grandes)Alta
'lbfgs'Bajo a moderadoModerada
'fin-diff-grads'BajoModerada
'HessianMultiplyFcn'Bajo (puede depender del código)Moderada
'HessianFcn'? (depende del código)Alta (depende del código)

Utilice la matriz hessiana 'bfgs' predeterminada a menos que

La razón por la que 'lbfgs' tiene solo eficiencia moderada es doble. Tiene actualizaciones Sherman-Morrison relativamente costosas. Y el salto de iteración resultante puede ser en cierto modo inexacto a consecuencia de la memoria limitada de 'lbfgs'.

La razón por la que 'fin-diff-grads' y HessianMultiplyFcn tienen solo eficiencia moderada es que utilizan un enfoque de gradiente conjugado. Estiman de forma precisa la matriz hessiana de la función objetivo, pero no generan el salto de iteración más preciso. Para obtener más información, consulte fmincon Interior Point Algorithm y su debate sobre el enfoque LDL y el enfoque de gradiente conjugado que se desea resolver Ecuación 38.

Temas relacionados