我有一个黑盒函数,f(x)和x的一系列值。 我需要找到x的最小值,其中f(x)= 0。
我知道,对于x的范围的开始,f(x)> 0,如果我有一个值f(x)<0 0我可以使用调节falsi或类似的根寻找方法来尝试确定f(x)= 0。
我知道f(x)是连续的,并且对于所讨论的范围应该只有0,1或2个根,但它可能具有局部最小值。
f(x)在某种程度上计算成本很高,而且我必须经常找到第一个根。
我正在考虑某种随机性的爬山以避免任何局部最小值,但是你怎么知道没有最小值小于零或者你是否还没找到它?我认为这个函数不应该有两个以上的最小点,但我不能完全肯定这个就足够了。
如果有帮助,x在这种情况下代表一个时间,而f(x)代表船舶与当时轨道(月球/行星)中的物体之间的距离。我需要第一点,它们彼此相距一定距离。
答案 0 :(得分:2)
我的方法听起来很复杂,但最终方法的计算时间远小于距离计算(评估你的f(x)
)。此外,它已经在现有的库中编写了很多实现。
那我该做什么:
f(x)
鉴于你的函数的性质(平滑,连续,表现良好)以及有0,1或2个根的信息,已经可以找到一个好的Chebychev多项式,其中有3个f(x)
的评估。 / p>
然后找到Chebychev系数的伴随矩阵的特征值;这些对应于Chebychev多项式的根。
如果所有都是虚构的,则有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]
您的范围在x
,5
用于查找多项式的点数(越高,越准确。等于所需的函数评估量),最后true
将绘制实际函数和Chebychev近似值的图(主要用于测试目的)。
现在,实施:
% 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
答案 1 :(得分:0)
答案 2 :(得分:0)
您的函数只有0,1或2个根,因此可以使用不保证第一个根的算法来完成。
r
,x的范围的开头为x0
。让d = (r-x0)/2
。d > 0
期间,计算f(r-d)
。 if f(r-d) > 0
,half d
(d := d / 2
)和循环。如果
f(r-d) <= 0
,逃避循环。d = 0
完成,则报告r
作为第一个根。如果d > 0
,请使用任何其他方法在x0
和r-d
之间找到根并报告。我假设了两个先决条件。
使用条件2,您可以证明如果没有f(r-d) < 0
,∀ x: x0 < x < r, f(x) > 0
这一点。
答案 3 :(得分:0)
您可以对R库rootSolve中的uniroot.all
函数进行少量更改。
uniroot.all <- function (f, interval, lower= min(interval),
upper= max(interval), tol= .Machine$double.eps^0.2,
maxiter= 1000, n = 100, nroots = -1, ... ) {
## error checking as in uniroot...
if (!missing(interval) && length(interval) != 2)
stop("'interval' must be a vector of length 2")
if (!is.numeric(lower) || !is.numeric(upper) || lower >=
upper)
stop("lower < upper is not fulfilled")
## subdivide interval in n subintervals and estimate the function values
xseq <- seq(lower,upper,len=n+1)
mod <- f(xseq,...)
## some function values may already be 0
Equi <- xseq[which(mod==0)]
ss <- mod[1:n]*mod[2:(n+1)] # interval where functionvalues change sign
ii <- which(ss<0)
for (i in ii) {
Equi <- c(Equi, uniroot(f, lower = xseq[i], upper = xseq[i+1] ,...)$root)
if (length(Equi) == nroots) {
return(Equi)
}
}
return(Equi)
}
然后像这样运行:
uniroot.all(f = your_function, interval = c(start, stop), nroots = 1)