Brent’s Root Finder

March 28, 2014

Here is our implementation of Brent’s algorithm: d is the value of the last step and e is the value of the second-last step; if the last step was a bisection then e = d. The bolded tests are those that force the bisection every three steps:

def brent(fun, x1, x2, args=(), xtol=1e-12, disp=False, maxiter=1000):
    """
    Bisection: k = log2((b-a)/tol) function eval.
    Dekker : upper bound: 2**k function eval.
    Brent : theoretical upper bound: (k+1)**2 ? 2
               practical upper bound: 3*(k+1)
    Example:
        tol = 1e-6
        b-a = 1
        Then k = 20
        Upperbounds
            Bisection: 20 (upperbound is also number iterations)
            Dekker : 2**20
            Brent : 63 (practical bound)
    """
    if disp: print "BRENT"
    a, b = float(x1), float(x2)
    fa, fb = fun(a, *args), fun(b, *args)
    ncalls = 2
    if fa * fb > 0.0:
        raise RootNotBracketedException(a, b, fa, fb)
    c, fc = b, fb
    for iters in range(maxiter):
        if disp: msg = ""
        if fc * fb > 0.0:
            if disp: msg += "c=a "
            c, fc = a, fa
            e = d = b - a
        if abs(fc) < abs(fb):
            if disp: msg += "swap "
            a, b, c, fa, fb, fc = b, c, b, fb, fc, fb
        tol1 = 2 * EPS * abs(b) + xtol
        xm = (c - b) / 2
        if abs(xm) <= tol1 or fb == 0:
            return b, iters, ncalls, 0
        if abs(e) >= tol1 and abs(fa) > abs(fb):
            s = fb / fa
            if a == c: # if a==c we cannot do quadratic interpolation, so try linear
                p = 2 * xm * s
                q = 1 - s
            else:
                # try quadratic interpolation
                q = fa / fc
                r = fb / fc
                p = s * (2 * xm * q * (q - r) - (b - a) * (r - 1))
                q = (q - 1) * (r - 1) * (s - 1)
        if p > 0:
            q = -q
        p = abs(p)
        if 2 * p < abs(e * q) and 2 * p < 3 * xm * q - abs(tol1 * q):
            if disp: msg += ("LINEAR" if a == c else "QUAD ")
            e = d
            d = p / q
        else:
            e = d = xm
            if disp: msg += "Bisect"
    else:
        e = d = xm
        if disp:
            msg += "Bisect"
    a, fa = b, fb
    if abs(d) > tol1:
        b += d
    else:
        b += __sign(tol1, xm)
    fb = fun(b, *args)
    ncalls += 1
    if disp:
        print "%15s a %8.5g %s b %8.5g %s c %8.5g %s " "fb %12.5g xm %8.5g" % (msg, a, __sss(fa), b, __sss(fb), c, __sss(fc), fb, xm)
    raise TooManyIterationsException(maxiter)

You can run the program at http://ideone.com/QXD932.

About these ads

Pages: 1 2

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 621 other followers

%d bloggers like this: