Main Content

fcn2optimexpr

将函数转换为优化表达式

说明

示例

[out1,out2,...,outN] = fcn2optimexpr(fcn,in1,in2,...,inK) 将函数 fcn(in1,in2,...,inK) 转换为具有 N 个输出的优化表达式。

示例

[out1,out2,...,outN] = fcn2optimexpr(fcn,in1,in2,...,inK,Name,Value) 使用一个或多个名称-值对组参量指定其他选项。例如,您可以通过传递 OutputSize 来保存函数计算。

示例

全部折叠

要在基于问题的方法中使用某 MATLAB® 函数,当该函数不是由支持的函数组成时,请首先将其转换为优化表达式。请参阅Supported Operations for Optimization Variables and Expressions将非线性函数转换为优化表达式

要使用目标函数 gamma(数学函数 Γ(x),阶乘函数的扩展),请创建一个优化变量 x 并在转换后的匿名函数中使用它。

x = optimvar('x');
obj = fcn2optimexpr(@gamma,x);
prob = optimproblem('Objective',obj);
show(prob)
  OptimizationProblem : 

	Solve for:
       x

	minimize :
       gamma(x)

要求解生成的问题,请给出初始点结构体并调用 solve

x0.x = 1/2;
sol =  solve(prob,x0)
Solving problem using fminunc.

Local minimum found.

Optimization completed because the size of the gradient is less than
the value of the optimality tolerance.
sol = struct with fields:
    x: 1.4616

对于更复杂的函数,请转换函数文件。函数文件 gammabrock.m 计算两个优化变量的一个目标。

type gammabrock
function f = gammabrock(x,y)
f = (10*(y - gamma(x)))^2 + (1 - x)^2;

在问题中包含此目标。

x = optimvar('x','LowerBound',0);
y = optimvar('y');
obj = fcn2optimexpr(@gammabrock,x,y);
prob = optimproblem('Objective',obj);
show(prob)
  OptimizationProblem : 

	Solve for:
       x, y

	minimize :
       gammabrock(x, y)


	variable bounds:
       0 <= x

gammabrock 函数是平方和。通过将函数表示为优化表达式的显式平方和,可以得到更高效的问题表示。

f = fcn2optimexpr(@(x,y)y - gamma(x),x,y);
obj2 = (10*f)^2 + (1-x)^2;
prob2 = optimproblem('Objective',obj2);

要查看效率差异,请求解 probprob2,并检查迭代次数的差异。

x0.x = 1/2;
x0.y = 1/2;
[sol,fval,~,output] = solve(prob,x0);
Solving problem using fmincon.

Local minimum found that satisfies the constraints.

Optimization completed because the objective function is non-decreasing in 
feasible directions, to within the value of the optimality tolerance,
and constraints are satisfied to within the value of the constraint tolerance.
[sol2,fval2,~,output2] = solve(prob2,x0);
Solving problem using lsqnonlin.

Local minimum found.

Optimization completed because the size of the gradient is less than
the value of the optimality tolerance.
fprintf('prob took %d iterations, but prob2 took %d iterations\n',output.iterations,output2.iterations)
prob took 21 iterations, but prob2 took 2 iterations

如果您的函数有若干个输出,您可以将它们用作目标函数的元素。在本例中,u 是一个 2×2 变量,v 是一个 2×1 变量,expfn3 有三个输出。

type expfn3
function [f,g,mineval] = expfn3(u,v)
mineval = min(eig(u));
f = v'*u*v;
f = -exp(-f);
t = u*v;
g = t'*t + sum(t) - 3;

创建适当大小的优化变量,并根据前两个输出创建一个目标函数。

u = optimvar('u',2,2);
v = optimvar('v',2);
[f,g,mineval] = fcn2optimexpr(@expfn3,u,v);
prob = optimproblem;
prob.Objective = f*g/(1 + f^2);
show(prob)
  OptimizationProblem : 

	Solve for:
       u, v

	minimize :
       ((arg2 .* arg3) ./ (1 + arg1.^2))

       where:

           [arg1,~,~] = expfn3(u, v);
           [arg2,~,~] = expfn3(u, v);
           [~,arg3,~] = expfn3(u, v);

您可以在后续约束表达式中使用 mineval 输出。

在基于问题的优化中,约束是两个优化表达式,它们之间有一个比较运算符(==<=>=)。您可以使用 fcn2optimexpr 创建一个或两个优化表达式。请参阅将非线性函数转换为优化表达式

创建 gammafn2 小于或等于 –1/2 的非线性约束。包含两个变量的此函数在 gammafn2.m 文件中。

type gammafn2
function f = gammafn2(x,y)
f = -gamma(x)*(y/(1+y^2));

创建优化变量,将函数文件转换为优化表达式,然后将约束表示为 confn

x = optimvar('x','LowerBound',0);
y = optimvar('y','LowerBound',0);
expr1 = fcn2optimexpr(@gammafn2,x,y);
confn = expr1 <= -1/2;
show(confn)
  gammafn2(x, y) <= -0.5

另外创建一个 gammafn2 大于或等于 x + y 的约束。

confn2 = expr1 >= x + y;

创建一个优化问题,并将这些约束放在该问题中。

prob = optimproblem;
prob.Constraints.confn = confn;
prob.Constraints.confn2 = confn2;
show(prob)
  OptimizationProblem : 

	Solve for:
       x, y

	minimize :

	subject to confn:
       gammafn2(x, y) <= -0.5

	subject to confn2:
       gammafn2(x, y) >= (x + y)

	variable bounds:
       0 <= x

       0 <= y

如果您的问题涉及使用一个常见的、耗时的函数来计算目标和非线性约束,您可以通过使用 ReuseEvaluation 名称-值参量来节省时间。rosenbrocknorm 函数计算罗森布罗克目标函数和参量的范数以用于约束 x24

type rosenbrocknorm
function [f,c] = rosenbrocknorm(x)
pause(1) % Simulates time-consuming function
c = dot(x,x);
f = 100*(x(2) - x(1)^2)^2 + (1 - x(1))^2;

创建一个二维优化变量 x。然后使用 fcn2optimexprrosenbrocknorm 转换为优化表达式,并将 ReuseEvaluation 名称-值参量设置为 true。要确保 fcn2optimexpr 保留 pause 语句,请将 Analysis 名称-值参量设置为 'off'

x = optimvar('x',2);
[f,c] = fcn2optimexpr(@rosenbrocknorm,x,...
    'ReuseEvaluation',true,'Analysis','off');

根据返回的表达式创建目标和约束表达式。在优化问题中包含目标和约束表达式。使用 show 检查问题。

prob = optimproblem('Objective',f);
prob.Constraints.cineq = c <= 4;
show(prob)
  OptimizationProblem : 

	Solve for:
       x

	minimize :
       [argout,~] = rosenbrocknorm(x)


	subject to cineq:
       arg_LHS <= 4

       where:

         [~,arg_LHS] = rosenbrocknorm(x);
     

从初始点 x0.x = [-1;1] 开始求解问题,对结果计时。

x0.x = [-1;1];
tic
[sol,fval,exitflag,output] = solve(prob,x0)
Solving problem using fmincon.

Local minimum found that satisfies the constraints.

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

<stopping criteria details>
sol = struct with fields:
    x: [2×1 double]

fval = 4.5793e-11
exitflag = 
    OptimalSolution

output = struct with fields:
              iterations: 44
               funcCount: 164
         constrviolation: 0
                stepsize: 4.3124e-08
               algorithm: 'interior-point'
           firstorderopt: 5.1691e-07
            cgiterations: 10
                 message: 'Local minimum found that satisfies the constraints.↵↵Optimization completed because the objective function is non-decreasing in ↵feasible directions, to within the value of the optimality tolerance,↵and constraints are satisfied to within the value of the constraint tolerance.↵↵<stopping criteria details>↵↵Optimization completed: The relative first-order optimality measure, 5.169074e-07,↵is less than options.OptimalityTolerance = 1.000000e-06, and the relative maximum constraint↵violation, 0.000000e+00, is less than options.ConstraintTolerance = 1.000000e-06.'
            bestfeasible: [1×1 struct]
     objectivederivative: "finite-differences"
    constraintderivative: "finite-differences"
                  solver: 'fmincon'

toc
Elapsed time is 165.623157 seconds.

以秒为单位的求解时间几乎与函数计算的次数相同。此结果表明求解器重用了函数值,并且没有浪费时间对同一点重新求值两次。

有关更广泛的示例,请参阅Objective and Constraints Having a Common Function in Serial or Parallel, Problem-Based。有关使用 fcn2optimexpr 的详细信息,请参阅将非线性函数转换为优化表达式

输入参数

全部折叠

要转换的函数,指定为函数句柄。

示例: @sin 指定正弦函数。

数据类型: function_handle

输入参量,指定为 MATLAB 变量。输入可以具有任何数据类型和任何大小。您可以在输入参量 in 中包含任何问题变量或数据;请参阅在基于问题的方法中传递额外的参数

数据类型: single | double | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64 | logical | char | string | struct | table | cell | function_handle | categorical | datetime | duration | calendarDuration | fi
复数支持:

名称-值参数

将可选的参量对组指定为 Name1=Value1,...,NameN=ValueN,其中 Name 是参量名称,Value 是对应的值。名称-值参量必须出现在其他参量之后,但参量对组的顺序无关紧要。

在 R2021a 之前,使用逗号分隔每个名称和值,并用引号将 Name 引起来。

示例: [out1,out2] = fcn2optimexpr(@fun,x,y,'OutputSize',[1,1],'ReuseEvaluation',true) 指定 out1out2 是无需重新计算即可由求解器在目标函数和约束函数之间重用的标量。

指示是否分析函数 fcn 以确定它是否完全由支持的运算组成(请参阅Supported Operations for Optimization Variables and Expressions),指定为 "on""off"

  • 如果您希望使用 fcn2optimexpr 来分析 fcn 并尽可能使用支持的运算来实现 fcn,请指定 "on"。此设定使 fcn 能够使用自动微分并选择合适的求解器,如 Solver 中所述。

  • 如果您不希望使用 fcn2optimexpr 来分析 fcn,并因此将 fcn 视为不使用自动微分的黑盒,请指定 "off"。在这种情况下,solve 仅使用 fminconfminunclsqnonlin 作为求解器。

有关 Analysis 的影响的详细信息,请参阅局限性

示例: [out1,out2] = fcn2optimexpr(@fun,x,"Analysis","off")

数据类型: char | string

报告函数分析详细信息,指定为 "off"(不报告)或 "on"(报告)。如果 Analysis"off",则不报告任何内容。

示例: [out1,out2] = fcn2optimexpr(@fun,x,"Display","on")

数据类型: char | string

输出表达式的大小,指定为:

  • 整数向量 - 如果函数有一个输出 out1,OutputSize 指定 out1 的大小。如果函数有多个输出 out1、…、outN,OutputSize 指定所有输出都具有相同大小。

  • 整数向量元胞数组 - 输出 outj 的大小是 OutputSize 的第 j 个元素。

注意

一个标量的大小为 [1,1]

如果未指定 'OutputSize' 名称-值对组参量,则 fcn2optimexpr 会将数据传递给 fcn,以确定输出的大小(请参阅算法)。通过指定 'OutputSize',您可以使 fcn2optimexpr 跳过此步骤,从而节省时间。此外,如果您未指定 'OutputSize',则当 fcn 的计算因任何原因失败时,fcn2optimexpr 也会失败。

示例: [out1,out2,out3] = fcn2optimexpr(@fun,x,'OutputSize',[1,1]) 指定 [out1,out2,out3] 这三个输出是标量。

示例: [out1,out2] = fcn2optimexpr(@fun,x,'OutputSize',{[4,4],[3,5]}) 指定 out1 的大小为 4×4,out2 的大小为 3×5。

数据类型: double | cell

重用值的指示符,指定为 false(不重用)或 true(重用)。

注意

Analysis = "on" 时,ReuseEvaluation 可能不起作用。

基于线程的并行池不支持 ReuseEvaluation

ReuseEvaluation 可以使您的问题求解运行得更快,例如,当目标和一些非线性约束依赖于共同的计算时。在这种情况下,求解器会存储值以便在需要时重用,避免重新计算该值。

可重用值会带来一些开销,因此最好只为共享某值的表达式启用可重用值。

示例: [out1,out2,out3] = fcn2optimexpr(@fun,x,"ReuseEvaluation",true,"Analysis","off") 允许在多次计算中使用 out1out2out3,每个计算点仅计算一次输出。

数据类型: logical

输出参量

全部折叠

输出参量,以 OptimizationExpression 形式返回。表达式的大小取决于输入函数。

局限性

Analysis 可能忽略非计算函数

  • Analysis 算法可能不包含非计算函数。算法的这一特点可能导致以下结果:

    • pause 语句被忽略。

    • 不影响结果的全局变量可能被忽略。例如,如果您使用全局变量来计算函数运行的次数,则可能会得到误导性的计数。

    • 如果该函数包含对 randrng 的调用,则该函数可能只执行第一次调用,以后的调用不会设置随机数流。

    • plot 调用可能不会在所有迭代中都更新图窗。

    • 可能不会在每次迭代时都将数据保存到 mat 文件或文本文件中。

  • 为了确保非计算函数按预期运行,请将 Analysis 名称-值参量设置为 "off"

有关详细信息,请参阅Limitations of Static Analysis

算法

全部折叠

分析

Analysis 参量采用默认设置 "on" 时,fcn2optimexpr 会执行几个步骤来尝试创建最高效的优化表达式。请参阅 fcn2optimexpr Algorithm Description 中的算法描述。

在问题对象中包含目标函数或非线性约束函数时,您有几种选择。

  • 使用重载。如果一个函数中的所有运算均为Supported Operations for Optimization Variables and Expressions,您可以直接对优化变量调用该函数。例如,

    prob.Objective = sin(3*x)*exp(-x-y);
  • 对未修改的函数使用 fcn2optimexpr。如果一个函数中有至少一项运算不受支持,则必须调用 fcn2optimexpr。例如,besselh 函数不受支持,因此要将其包含在目标函数中,必须使用 fcn2optimexpr

    prob.Objective = fcn2optimexpr(@(z)besselh(3,z),x);
  • 修改函数,使其内部 for 循环出现在单独的函数中。这样做可以通过静态分析加快循环执行速度。请参阅Create for Loop for Static AnalysisStatic Analysis of Optimization Expressions

  • fcn2optimexpr 中的 Analysis 参量设置为 "off"。这样做会使得 fcn2optimexpr 将函数封装为黑盒,这是一项速度很快的操作。得到的表达式无法利用自动微分(请参阅Automatic Differentiation Background),因此会导致求解器使用更多函数计算来进行有限差分梯度估计。

输出大小

为了在未指定 OutputSize 时查找每个返回的表达式的输出大小,fcn2optimexpr 在以下点为问题变量的每个元素计算函数。

变量特性计算点
有限上界 ub 和有限下界 lb(lb + ub)/2 + ((ub - lb)/2)*eps
有限下界和无上界lb + max(1,abs(lb))*eps
有限上界和无下界ub - max(1,abs(ub))*eps
没有边界1 + eps
变量指定为整数之前给出的点的 floor

计算点可能会导致函数计算错误。要避免此错误,请指定 OutputSize

版本历史记录

在 R2019a 中推出