我有一个黑匣子函数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)表示该时间船与轨道上的物体(月球/行星)之间的距离。我需要它们之间相距一定距离的第一点。
我的方法听起来很复杂,但最终该方法的计算时间将比距离计算(您的f(x))的计算要少得多。另外,已有的库中已经编写了很多实现。
f(x)
所以我会怎么做:
给定函数的性质(平滑,连续,否则行为良好),并且有0,1或2个根的信息,可以通过对3进行求值来找到一个好的Chebychev多项式f(x)。
然后找到切比雪夫系数的伴随矩阵的特征值;这些对应于切比雪夫多项式的根。
如果所有都是虚构的,则存在0个根。如果存在真正的根,请检查两个是否相等(您所说的“稀有”情况)。否则,所有真实特征值都是根。最低的是您要寻找的根。
然后使用Newton-Raphson进行细化(如有必要,或使用更好的Chebychev多项式)。的导数f可以使用中心差来近似
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]你的范围x,5点使用的用于寻找多项式(越高,越准确。的Equals需要功能评估的量),最后的数字true会使得实际功能的情节和切比雪夫逼近它(主要用于测试)。
[x_min,x_max]
x
5
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