确定fsolve的收敛速度 - Matlab

时间:2014-11-07 01:09:51

标签: matlab optimization numerical-methods convergence

假设我正在解决一个非线性方程组。一个简单的例子是:

function example
    x0 = [15; -2];
    options = optimoptions('fsolve','Display','iter','TolFun',eps,'TolX',eps);
    [x,fval,exitflag,output] = fsolve(@P1a,x0,options);
end

function f1 = P1a(x)
    f1 = [x(1)+x(2)*(x(2)*(5-x(2))-2)- 13; x(1)+x(2)*(x(2)*(1+x(2))-14)-29];
end

如何确定收敛率? 'Display''iter'向我展示了每一步的标准,但我无法找到提取这些值的方法。 (对于这个特定的例子,我认为fsolve不会收敛到正确的解决方案,而是收敛到局部最小值。但这不是问题。我只是想找到一种估算收敛速度的方法。)

1 个答案:

答案 0 :(得分:0)

你可以从fsolve获得足够的资金。但是,您需要做一些工作。阅读'OutputFcn'选项并为Matlab的优化方法编写output functions。这与Matlab的ODE求解器使用的同名选项类似。这是一个复制'Display','iter'的{​​{1}}选项值的示例(具体为默认的fsolve算法):

'trust-region-dogleg'

然后您可以通过以下方式调用此方法:

function stop = outfun(x,optimValues,state)
% See private/trustnleqn
stop = false;

switch state
    case 'init'
        header = sprintf(['\n                                         Norm of      First-order   Trust-region\n',...
                          ' Iteration  Func-count     f(x)          step         optimality    radius']);
        disp(header);
    case 'iter'
        iter = optimValues.iteration;               % Iteration
        numFevals = optimValues.funccount;          % Func-count
        F = optimValues.fval;                       % f(x)
        normd = optimValues.stepsize;               % Norm of step
        normgradinf = optimValues.firstorderopt;    % First-order optimality
        Delta = optimValues.trustregionradius;      % Trust-region radius

        if iter > 0
            formatstr = ' %5.0f      %5.0f   %13.6g  %13.6g   %12.3g    %12.3g';
            iterOutput = sprintf(formatstr,iter,numFevals,F'*F,normd,normgradinf,Delta);
        else
            formatstr0 = ' %5.0f      %5.0f   %13.6g                  %12.3g    %12.3g';
            iterOutput = sprintf(formatstr0,iter,numFevals,F'*F,normgradinf,Delta);
        end
        disp(iterOutput);
    case 'done'

    otherwise

end

这仍然只是打印到命令窗口。从这里开始,创建一个可以将数据写入数组,文件或其他数据结构的输出函数。您可以通过global variable(通常不是一个好主意)来实现这一目标:

function example
P1a=@(x)[x(1)+x(2)*(x(2)*(5-x(2))-2)- 13; x(1)+x(2)*(x(2)*(1+x(2))-14)-29];
x0 = [15; -2];
opts = optimoptions('fsolve','Display','off','OutputFcn',@outfun,'TolFun',eps,'TolX',eps);
[x,fval,exitflag,output] = fsolve(P1a,x0,opts);

然后在调用function stop = outfun2(x,optimValues,state) stop = false; global out; % Global variable, define in main function too switch state case 'init' out = []; case 'iter' iter = optimValues.iteration; % Iteration numFevals = optimValues.funccount; % Func-count F = optimValues.fval; % f(x) normd = optimValues.stepsize; % Norm of step normgradinf = optimValues.firstorderopt; % First-order optimality Delta = optimValues.trustregionradius; % Trust-region radius out = [out;iter numFevals F'*F normd normgradinf Delta]; case 'done' otherwise end 之前,在主函数中声明global out;。您还可以通过使输出函数为nested function来实现此目的,在这种情况下,fsolve数组将与外部主函数共享。

第二个输出函数示例执行动态内存分配,而不是重新分配整个out数组。由于我们和算法都不知道收敛需要多少次迭代,因此无法解决这个问题。但是,对于几百次迭代,动态内存分配将非常快。

我将离开"确定收敛速度"现在你手头有工具......