Main Content

当求解器失败时

迭代或函数计算次数太多

求解器停止,因为它在将目标函数最小化至要求的容差之前达到了迭代或函数计算次数的限制。要继续,请尝试下列一项或多项操作。

1.启用迭代输出
2.放宽容差
3.从不同点启动求解器
4.检查目标和约束函数定义
5.中心化和缩放问题
6.提供梯度或雅可比矩阵
7.提供黑塞函数

1.启用迭代输出

Display 选项设置为 'iter'。此设置显示求解器迭代的结果。

要在 MATLAB® 命令行中启用迭代输出,请输入

options = optimoptions('solvername','Display','iter');

使用 options 结构体调用求解器。

有关迭代输出的示例,请参阅解释结果

在迭代输出中查看的内容

  • 查看目标函数(Fvalf(x)Resnorm)是否呈下降态势。呈下降态势表示有进展。

  • 检查约束违反值 (Max constraint) 以确保它朝着 0 方向呈下降态势。呈下降态势表示有进展。

  • 查看一阶最优性是否朝着 0 方向呈下降态势。呈下降态势表示有进展。

  • 查看 Trust-region radius 是否降至一个小值。此下降指示目标可能不平滑。

操作

  • 如果求解器看起来有进展,请:

    1. MaxIterations 和/或 MaxFunctionEvaluations 设置为大于默认值的值。您可以在求解器的函数参考页的 Options 表中查看默认值。

    2. 从求解器的最后一个计算点开始运行求解器。

  • 如果求解器没有进展,请尝试列出的其他建议。

2.放宽容差

例如,如果 StepToleranceOptimalityTolerance 太小,求解器可能无法意识到它已达到最小值;从而可能会无限期地进行徒劳的迭代。

要在命令行中更改容差,请使用 optimoptions,如设置和更改优化选项中所述。

FiniteDifferenceStepSize 选项(或 DiffMaxChangeDiffMinChange 选项)会影响求解器的进展。这些选项控制导数估计的有限差分中的步长。

3.从不同点启动求解器

请参阅更改初始点

4.检查目标和约束函数定义

例如,检查您的目标和非线性约束函数在某些点处是否返回正确的值。请参阅检查您的目标和约束函数。检查以确保不可行点不会导致函数中出现错误;请参阅迭代可能违反约束

5.中心化和缩放问题

当每个坐标对目标函数和约束函数的影响大致相同时,求解器运行更可靠。请将坐标方向与适当的标量相乘,以平衡每个坐标的效果。在某些坐标中添加适当的值,以均衡其大小。

示例:中心化和缩放.  假设需要求解 1e6*x(1)^2 + 1e-6*x(2)^2 的最小值:

f = @(x) 10^6*x(1)^2 + 10^-6*x(2)^2;

使用 fminunc 'quasi-newton' 算法最小化 f

opts = optimoptions('fminunc','Display','none','Algorithm','quasi-newton');
x = fminunc(f,[0.5;0.5],opts)

x =
         0
    0.5000

结果不正确;缩放不佳妨碍了获得理想的解。

缩放问题。进行以下设置

D = diag([1e-3,1e3]);
fr = @(y) f(D*y);
y = fminunc(fr, [0.5;0.5], opts)

y =
     0
     0 % the correct answer

同样,中心化不佳也会妨碍获得理想的解。

fc = @(z)fr([z(1)-1e6;z(2)+1e6]); % poor centering
z = fminunc(fc,[.5 .5],opts)

z =
  1.0e+005 *
   10.0000  -10.0000 % looks good, but...

z - [1e6 -1e6] % checking how close z is to 1e6

ans =

   -0.0071    0.0078 % reveals a distance


fcc = @(w)fc([w(1)+1e6;w(2)-1e6]); % centered

w = fminunc(fcc,[.5 .5],opts)

w =
     0     0 % the correct answer

6.提供梯度或雅可比矩阵

如果不提供梯度或雅可比矩阵,求解器会通过有限差分来估计梯度和雅可比矩阵。因此,提供这些导数可以节省计算时间,并可以提高准确度。基于问题的方法可以自动提供梯度;请参阅 Automatic Differentiation in Optimization Toolbox

对于约束问题,提供梯度还有另一个优势。求解器可以到达点 x,这说明 x 是可行点,但 x 附近的有限差分总是导致不可行点。在这种情况下,求解器可能会失败或过早停止。提供梯度可允许求解器继续。

在文件中为目标函数和非线性约束函数提供梯度或雅可比矩阵。有关语法的详细信息,请参阅编写标量目标函数编写向量和矩阵目标函数非线性约束

要检查梯度或雅可比函数是否正确,请使用 checkGradients 函数,如Checking Validity of Gradients or Jacobians中所述。

如果您有 Symbolic Math Toolbox™ 许可证,您可以通过编程方式计算梯度和黑塞矩阵。有关示例,请参阅Calculate Gradients and Hessians Using Symbolic Math Toolbox

有关使用梯度和雅可比矩阵的示例,请参阅使用梯度和黑塞矩阵的最小化带梯度的非线性约束Calculate Gradients and Hessians Using Symbolic Math Toolbox求解不含和含雅可比矩阵的非线性方程组Large Sparse System of Nonlinear Equations with Jacobian。对于基于问题的方法中的自动微分,请参阅Effect of Automatic Differentiation in Problem-Based Optimization

7.提供黑塞函数

当您提供黑塞矩阵时,求解器的运行通常更可靠,迭代次数也更少。

以下求解器和算法接受黑塞矩阵:

如果您有 Symbolic Math Toolbox 许可证,您可以通过编程方式计算梯度和黑塞矩阵。有关示例,请参阅Calculate Gradients and Hessians Using Symbolic Math Toolbox。要在基于问题的方法中提供黑塞矩阵,请参阅Supply Derivatives in Problem-Based Workflow

收敛于不可行点

通常,您得到此结果的原因是求解器在 ConstraintTolerance 容差内找不到满足所有约束的点。但求解器可能已找到或开始于某个可行点,收敛于一个不可行点。如果求解器失去可行性,请参阅求解器失去可行性。如果 quadprog 返回此结果,请参阅quadprog 收敛于不可行点

要在求解器找不到可行点时继续,请尝试以下一项或多项操作。

1.检查线性约束
2.检查非线性约束

1.检查线性约束

通过求解线性规划问题,尝试找到满足边界和线性约束的点。

  1. 定义目标函数始终为零的线性规划问题:

    f = zeros(size(x0)); % assumes x0 is the initial point
  2. 求解线性规划问题,查看是否有可行点:

    xnew = linprog(f,A,b,Aeq,beq,lb,ub);
  3. 如果存在可行点 xnew,请使用 xnew 作为初始点,然后重新运行原始问题。

  4. 如果没有可行点,则说明您的问题的表示不好。检查您的边界和线性约束的定义。有关检查线性约束的详细信息,请参阅Investigate Linear Infeasibilities

2.检查非线性约束

在确保边界和线性约束可行(包含一个满足所有约束的点)后,检查非线性约束。

  • 将目标函数设置为零:

    @(x)0

    使用所有约束和零目标运行优化。如果您找到可行点 xnew,请设置 x0 = xnew,然后重新运行您的原始问题。

  • 如果使用零目标函数找不到可行点,请使用具有几个初始点的零目标函数。

    • 如果您找到可行点 xnew,请设置 x0 = xnew,然后重新运行您的原始问题。

    • 如果找不到可行点,请尝试使用 fmincon,并将 EnableFeasibilityMode 选项设置为 true,将 SubproblemAlgorithm 选项设置为 'cg',如使用可行性模式获得解中所示。请使用这些选项尝试几个初始点。

    • 如果您仍找不到可行点,请尝试放宽约束,下面将对此进行讨论。

尝试放宽您的非线性不等式约束,然后再收紧它们。

  1. 更改非线性约束函数 c 以返回 c-Δ,其中 Δ 为正数。此更改使您的非线性约束更容易被满足。

  2. 使用原始目标函数或零目标函数,为新约束函数寻找可行点。

    1. 如果您找到可行点,则

      1. 降低 Δ

      2. 从先前找到的点开始,为新约束函数寻找可行点。

    2. 如果您找不到可行点,请尝试增大 Δ 并重新寻找。

如果您找不到可行点,则说明您的问题可能确实不可行,也就是说您的问题不存在解。请再次检查所有约束定义。

求解器失去可行性

如果求解器从可行点开始,但收敛于不可行点,请尝试以下方法。

  • 尝试不同算法。fmincon 'sqp''interior-point' 算法通常是最稳健的,因此请先尝试这两种算法。

  • 收紧边界。尽可能给出最高的 lb 和最低的 ub 向量。这可以帮助求解器保持可行性。fmincon 'sqp''interior-point' 算法在每次迭代中都遵守边界,因此严格的边界有助于完成整个优化过程。

quadprog 收敛于不可行点

您收到这条消息通常是因为线性约束不一致,或近乎奇异。要检查可行点是否存在,请创建具有相同约束和零目标函数向量 f 的线性规划问题。使用 linprog 'dual-simplex' 算法进行求解:

options = optimoptions('linprog','Algorithm','dual-simplex');
x = linprog(f,A,b,Aeq,beq,lb,ub,options)

如果 linprog 找不到可行点,则说明您的问题确实不可行。

如果 linprog 找到可行点,则请尝试不同的 quadprog 算法。或者,更改一些容差,如 StepToleranceConstraintTolerance,然后再次求解问题。

问题无界

求解器达到目标函数小于目标极限容差的点。

  • 您的问题可能确实无界。换句话说,存在一些点 xi 符合

    lim f(xi) = –∞。

    并且使得所有 xi 都满足问题约束。

  • 检查您的问题表示是否正确。求解器会尝试对目标函数进行最小化;如果您需要最大值,请将您的目标函数改为其负函数。有关示例,请参阅对目标进行最大化

  • 尝试缩放或中心化您的问题。请参阅中心化和缩放问题

  • 通过使用 optimoptions 降低 ObjectiveLimit 容差的值,放宽目标极限容差。

fsolve 无法求解方程

fsolve 可能会由于各种原因而无法求解方程。以下是一些如何继续求解的建议:

  1. 尝试更改初始点fsolve 依赖于初始点。通过为它提供不同的初始点,可以增加成功的机会。

  2. 检查方程的定义,以确保它是平滑的。对于具有不连续梯度的方程(例如绝对值),fsolve 可能无法收敛。fsolve 对于具有不连续性的函数可能无法收敛。

  3. 检查方程是否为“方阵”,即输入和输出的维数相等(未知数的数目与方程的值的数目相同)。

  4. 更改容差,尤其是 OptimalityToleranceStepTolerance。如果您尝试通过将容差设置为非常小的值来获得高准确度,fsolve 可能无法收敛。如果您设置的容差太高,fsolve 可能无法准确求解方程。

  5. 检查问题定义。有些问题没有实数解,例如 x^2 + 1 = 0。如果您可以接受复数解,请尝试将初始点设置为复数值。当初始点为实数时,fsolve 不会尝试寻找复数解。

相关主题