I have a black box function, f(x) and a range of values for x. I need to find the lowest value of x for which f(x) = 0.
I know that for the start of the range of x, f(x) > 0, and if I had a value for which f(x) < 0 I could use regula falsi, or similar root finding methods, to try determine f(x)=0.
I know f(x) is continuous, and should only have 0,1 or 2 roots for the range in question, but it might have a local minimum.
f(x) is somewhat computationally expensive, and I'll have to find this first root a lot.
I was thinking some kind of hill climbing with a degree of randomness to avoid any local minimums, but then how do you know if there was no minimum less than zero or if you just haven't found it yet? I think the function shouldn't have more than two minimum points, but I can't be absolutely certain of that enough to rely on it.
If it helps, x in this case represents a time, and f(x) represents the distance between a ship and a body in orbit (moon/planet) at that time. I need the first point where they are a certain distance from each other.
Your function has only 0, 1 or 2 roots, so it can be done using an algorithm it doesn't ensure the first root.
r
and beginning of the range of the x isx0
. letd = (r-x0)/2
.d > 0
, calculatef(r-d)
. iff(r-d) > 0
, halfd
(d := d / 2
) and loop. iff(r-d) <= 0
, escape the loop.d = 0
, reportr
as the first root. ifd > 0
, find a root betweenx0
andr-d
by using any other method and report it.I assumed two prerequiesite conditions.
Using condition 2, you can prove that if there is no point such that
f(r-d) < 0
,∀ x: x0 < x < r, f(x) > 0
.My method will sound pretty complicated, but in the end the computation time of the method will be far smaller than the distance calculations (evaluation of your
f(x)
). Also, there are quite many implementations of it already written up in existing libraries.So what I would do:
f(x)
with a Chebychev polynomialGiven the nature of your function (smooth, continuous, otherwise well-behaved) and the information that there's 0,1 or 2 roots, a good Chebychev polynomial can already be found with 3 evaluations of
f(x)
.Then find the eigenvalues of the companion matrix of the Chebychev coefficients; these correspond to the roots of the Chebychev polynomial.
If all are imaginary, there's 0 roots. If there are some real roots, check if two are equal (that "rare" case you spoke of). Otherwise, all real eigenvalues are roots; the lowest one of which is the root you seek.
Then use Newton-Raphson to refine (if necessary, or use a better Chebychev polynomial). Derivatives of
f
can be approximated using central differencesI have an implementation of the Chebychev routines in Matlab/Octave (given below). Use like this:
with
[x_min,x_max]
your range inx
,5
the number of points to use for finding the polynomial (the higher, the more accurate. Equals the amount of function evaluations needed), and the lasttrue
will make a plot of the actual function and the Chebychev approximation to it (mainly for testing purposes).Now, the implementation:
You could use the secant method which is a discrete version of Newton's method.
The root is estimated by calculating the line between two points (= the secant) and its crossing of the X axis.
You could make a small change to the
uniroot.all
function from the R library rootSolve.And run it like this: