小编典典

查找黑盒函数的第一根,或同一函数的任何负值

algorithm

我有一个黑匣子函数f(x)和x的取值范围。我需要找到f(x)= 0的x的最小值。

我知道对于x范围的开始,f(x)> 0,如果我有一个f(x)<0的值,则可以使用regula falsi或类似的求根方法来尝试确定f( x)= 0。

我知道f(x)是连续的,并且对于所讨论的范围,应该只有0.1或2个根,但是它可能具有局部最小值。

f(x)在计算上有些昂贵,我将不得不找到很多第一个根。

我当时在考虑某种程度的随机性爬山以避免任何局部最小值,但是您如何知道最小值是否小于零,或者您是否尚未找到最小值?我认为该函数不应有两个以上的最低点,但是我不能绝对肯定要依赖它。

如果有帮助,在这种情况下,x表示时间,而f(x)表示该时间船与轨道上的物体(月球/行星)之间的距离。我需要它们之间相距一定距离的第一点。


阅读 275

收藏
2020-07-28

共1个答案

小编典典

我的方法听起来很复杂,但最终该方法的计算时间将比距离计算(您的f(x))的计算要少得多。另外,已有的库中已经编写了很多实现。

所以我会怎么做:

  • f(x)用Chebychev多项式近似
  • 找到该多项式的实根
  • 如果找到任何根,请使用这些根作为更精确的根查找器中的初始估计值(如果需要)

给定函数的性质(平滑,连续,否则行为良好),并且有0,1或2个根的信息,可以通过对3进行求值来找到一个好的Chebychev多项式f(x)

然后找到切比雪夫系数的伴随矩阵的特征值;这些对应于切比雪夫多项式的根。

如果所有都是虚构的,则存在0个根。如果存在真正的根,请检查两个是否相等(您所说的“稀有”情况)。否则,所有真实特征值都是根。最低的是您要寻找的根。

然后使用Newton-Raphson进行细化(如有必要,或使用更好的Chebychev多项式)。的导数f可以使用中心差来近似

f'(x) = ( f(x+h)-f(h-x) ) /2/h     (for small h)

我在Matlab / Octave(如下所示)中实现了Chebychev例程。像这样使用:

R = FindRealRoots(@f, x_min, x_max, 5, true,true);

[x_min,x_max]你的范围x5点使用的用于寻找多项式(越高,越准确。的Equals需要功能评估的量),最后的数字true会使得实际功能的情节和切比雪夫逼近它(主要用于测试)。

现在,执行:

% FINDREALROOTS     Find approximations to all real roots of any function 
%                   on an interval [a, b].
%
% USAGE:
%    Roots = FindRealRoots(funfcn, a, b, n, vectorized, make_plot)
%
% FINDREALROOTS() approximates all the real roots of the function 'funfcn' 
% in the interval [a,b]. It does so by finding the roots of an [n]-th degree 
% Chebyshev polynomial approximation, via the eignevalues of the associated 
% companion matrix. 
%
% When the argument [vectorized] is [true], FINDREALROOTS() will evaluate 
% the function 'funfcn' at all [n] required points in the interval 
% simultaneously. Otherwise, it will use ARRAFUN() to calculate the [n] 
% function values one-by-one. [vectorized] defaults to [false]. 
%
% When the argument [make_plot] is true, FINDREALROOTS() plots the 
% original function and the Chebyshev approximation, and shows any roots on
% the given interval. Also [make_plot] defaults to [false]. 
%
% All [Roots] (if any) will be sorted.
% 
% First version 26th May 2007 by Stephen Morris, 
% Nightingale-EOS Ltd., St. Asaph, Wales.
%
% Modified 14/Nov (Rody Oldenhuis)
%
% See also roots, eig.

function Roots = FindRealRoots(funfcn, a, b, n, vectorized, make_plot)

    % parse input and initialize.
    inarg = nargin; 
    if n <= 2, n = 3; end                    % Minimum [n] is 3:    
    if (inarg < 5), vectorized = false; end  % default: function isn't vectorized
    if (inarg < 6), make_plot = false; end   % default: don't make plot

    % some convenient variables
    bma = (b-a)/2;  bpa = (b+a)/2;  Roots = [];

    % Obtain the Chebyshev coefficients for the function
    %
    % Based on the routine given in Numerical Recipes (3rd) section 5.8;
    % calculates the Chebyshev coefficients necessary to approximate some
    % function over the interval [a,b]

    % initialize 
    c = zeros(1,n);  k=(1:n)';  y = cos(pi*((1:n)-1/2)/n); 
    % evaluate function on Chebychev nodes
    if vectorized
        f = feval(funfcn,(y*bma)+bpa);
    else
        f = arrayfun(@(x) feval(funfcn,x),(y*bma)+bpa);
    end

    % compute the coefficients
    for j=1:n, c(j)=(f(:).'*(cos((pi*(j-1))*((k-0.5)/n))))*(2-(j==1))/n; end

    % coefficients may be [NaN] if [inf]
    % ??? TODO - it is of course possible for c(n) to be zero...
    if any(~isfinite(c(:))) || (c(n) == 0), return; end

    % Define [A] as the Frobenius-Chebyshev companion matrix. This is based
    % on the form given by J.P. Boyd, Appl. Num. Math. 56 pp.1077-1091 (2006).
    one = ones(n-3,1);
    A = diag([one/2; 0],-1) + diag([1; one/2],+1);
    A(end, :) = -c(1:n-1)/2/c(n);
    A(end,end-1) = A(end,end-1) + 0.5;

    % Now we have the companion matrix, we can find its eigenvalues using the
    % MATLAB built-in function. We're only interested in the real elements of
    % the matrix:
    eigvals = eig(A);  realvals = eigvals(imag(eigvals)==0);

    % if there aren't any real roots, return
    if isempty(realvals), return; end

    % Of course these are the roots scaled to the canonical interval [-1,1]. We
    % need to map them back onto the interval [a, b]; we widen the interval just
    % a tiny bit to make sure that we don't miss any that are right on the 
    % boundaries.
    rangevals = nonzeros(realvals(abs(realvals) <= 1+1e-5));

    % also sort the roots
    Roots = sort(rangevals*bma + bpa);

    % As a sanity check we'll plot out the original function and its Chebyshev
    % approximation: if they don't match then we know to call the routine again
    % with a larger 'n'.
    if make_plot
        % simple grid
        grid = linspace(a,b, max(25,n));
        % evaluate function
        if vectorized
            fungrid = feval(funfcn, grid);
        else
            fungrid = arrayfun(@(x) feval(funfcn,x), grid);
        end        
        % corresponding Chebychev-grid (more complicated but essentially the same)
        y = (2.*grid-a-b)./(b-a); d = zeros(1,length(grid)); dd = d;
        for j = length(c):-1:2, sv=d; d=(2*y.*d)-dd+c(j); dd=sv; end, chebgrid=(y.*d)-dd+c(1);
        % Now make plot
        figure(1), clf,  hold on
        plot(grid, fungrid ,'color' , 'r');
        line(grid, chebgrid,'color' , 'b'); 
        line(grid, zeros(1,length(grid)), 'linestyle','--')
        legend('function', 'interpolation')
    end % make plot

end % FindRealRoots
2020-07-28