在MATLAB中求解多个非线性独立方程的最快方法?

时间:2017-07-10 18:10:22

标签: matlab performance equation-solving nonlinear-optimization

MATLAB有两种方法可以解决非线性方程:

  • fzero:解决单个非线性方程
  • fsolve:解决非线性方程组

因此,可以使用以下方法来求解n非线性独立方程组:

  1. 使用循环使用fzero
  2. 分别求解方程式
  3. 使用循环使用fsolve
  4. 分别求解方程式
  5. 使用fsolve一起解决问题
  6. 我的直觉是:

    • 对于大n,循环方法比单个系统更快,因为复杂度(梯度计算)为0(n ^ 2)
    • 对于小n,循环可能会慢一些,因为循环在MATLAB中有很高的开销,并且可能有一些不变的启动时间
    • fzerofsolve更快,因为它专门用于单个非线性方程。

    问题:解决此问题的最快方法是什么?应该使用哪些选项来加快流程?

    相关主题

2 个答案:

答案 0 :(得分:5)

评估某种方法性能的最佳方法是编写基准。考虑四种情况:

  1. loop fzero :使用循环使用fzero
  2. 分别求解方程式
  3. loop fsolve :使用循环使用fsolve
  4. 分别求解方程式
  5. 默认fsolve :将方程一起解算为一个方程组
  6. 独立fsolve :与默认fsolve 相同,但specifies that the equations are independent
  7. f = @(x) x.^2-1; % the set of non-linear equations
    ns = 1:1:100; % the sizes for which the benchmark is performed
    options=optimset('Display','off'); % disable displaying
    
    figure
    hold on
    plot(ns, loopFSolve(f, ns, options), 'DisplayName', 'loop fsolve')
    plot(ns, loopFZero(f, ns, options), 'DisplayName', 'loop fzero')
    plot(ns, defaultFSsolve(f, ns, options), 'DisplayName', 'default fsolve')
    plot(ns, independentFSolve(f, ns, options), 'DisplayName', 'independent fsolve')
    
    legend ('Location', 'northwest')
    
    function t = loopFZero(f, ns, options)
      t1 = timeit(@() fzero(f, rand(1), options));
      t = ns * t1;
    end
    
    function t = loopFSolve(f, ns, options)
      t1 = timeit(@() fsolve(f, rand(1), options));
      t = ns * t1;
    end
    
    function t = defaultFSsolve(f, ns, options)
      t = zeros(size(ns));
      for i=1:length(ns)
        n = ns(i);
        un = rand(n, 1);
        t(i) = timeit(@() fsolve(f, un, options));
      end
    end
    
    function t = independentFSolve(f, ns, options)
      t = zeros(size(ns));
      for i=1:length(ns)
        n = ns(i);
        un = rand(n, 1);
        options.Algorithm = 'trust-region-reflective';
        options.JacobPattern = speye(n);
        options.PrecondBandWidth = 0;
    
        t(i) = timeit(@() fsolve(f, un, options));
      end
    end
    

    <强>结果

    所有数字都显示了完整系统的计算时间n,方程组的数量。

    前两个数字将n绘制为最多1000个,间隔为100.最后两个数字将n绘制为最多100个,间隔为1.对于每个,第二个图是与第一个相同,但没有循环fzero ,因为它比其他的慢得多。

    enter image description here enter image description here enter image description here enter image description here结论

    1. loop fsolve :不要使用它,启动时间太长
    2. 循环fzero :您可以将它用于小型nn < ~20的最快方法)
    3. 默认fsolve :您可以将其用于相对较小的n~20 < n < ~50的最快方法,但与2和3的差异相对较小)。
    4. 独立的fsolve :您应该将它用于大型n~50 < n的最快方法)
    5. 一般,您应该使用独立的fsolve ,仅适用于小n 循环fzero 可以代替使用,即使用fsolve具有以下选项:

      options.Algorithm = 'trust-region-reflective';
      options.JacobPattern = speye(n);
      options.PrecondBandWidth = 0;
      

      懒人可能只使用默认fsolve ,因为它对于中等数量的等式具有合理的性能(n < ~200

      <强>说明

      • 请注意,默认fsolve 的时间复杂度为O(n ^ 2),其他为O(n)。
      • 请注意fzerofsolve在某些边界情况下可能会有不同的行为,因为fzero搜索符号更改的位置,因此x^2找不到select d.name, group_concat(c.name) from documents d join document_document_category dc on dc.document_id = d.id join document_categories c on dc.document_category_id = c.id group by d.name 的解决方案

答案 1 :(得分:1)

我添加这个答案是为了详细说明我上面的评论。根据我目前的经验,最快的方法是使用文件交换中可用的 fzero 的矢量化版本:Link to vectorized bisection code

这里有几个基准将其性能与 (i) 循环 fzero 和 (ii) 独立 fsolve 进行比较。

f = @(x) x.^2-1; %the set of non-linear equations
ns = 1e5; %size of the problem

% method 1: looped fzero
t = timeit(@() fzero(f, rand(1)));
loopFZero = t*ns

% method 2: independent fsolve
options=optimset('Display','off'); % disable displaying
options.Algorithm = 'trust-region-reflective';
options.JacobPattern = speye(ns);
options.PrecondBandWidth = 0;
indepFSolve = timeit(@() fsolve(f, rand(ns,1), options))

% method 3: vectorized bisection, available here:
% https://www.mathworks.com/matlabcentral/fileexchange/28150-bisection-method-root-finding
vecBisection = timeit(@() bisection(f, zeros(ns,1), 2))

结果

%---------------
% ns = 10

loopFZero =

    0.0027


indepFSolve =

    0.0049


vecBisection =

   5.0978e-05

%---------------
% ns = 1e5

loopFZero =

   28.7574


indepFSolve =

    7.7601


vecBisection =

    0.0013