def newton(f, xo, ft, **keyargs): """Returns an approximation of the function's root via newton's method. Assumes that the function is appropriate for this method, i.e., in the neighborhood of xo, the function - Is continuous - Has one and only one root - Has it's first derivative != 0 f: The function. (python-compatible function) xo: The initial guess. (float) ft: The tolerance function. (python-compatible function) **keyargs: Any keyword:value the tolerance function might take. (dict) E.g. newton(fx, 1.5, aux.tol_iter, n=10**1) Note: It might be necessary to modify this function for some tolerance functions. As is, it checks if ft(keyargs) is True in order to stop. """ if ft(**keyargs): return xo else: try: return newton(f, xo - (f(xo) / d_n(f, 1)(xo)), ft, **keyargs) except ZeroDivisionError: raise ValueError('d/dx f must be != 0')
def t_rootfinding(): print 'rootfinding...' def test_it(expected, result, max_error): diff = abs(expected-result) if diff < max_error: print 'OK' else: print 'FAIL' print ' Expected:', expected print ' Got:', result print ' Difference:', diff print ' Tolerance:', max_error def rp(x, k=1, min=-1, max=1): """Random polynomial of degree k at x""" coeffs = numpy.random.uniform(min, max, size=k+1) return sum([coeffs[i]*x**i for i in xrange(len(coeffs))]) x = sympy.symbols('x') # Number of tests n = 4 # Maximum iterations iter = 10 # How much can the tests differ from the expected results? Adjust # according to the method and number of iterations. max_error = 10**-8 # For simplicity, test only for degree 1 polynomials with roots in a known # interval print ' Newton...' i = 0 while i < n: p = sympy.lambdify(x, rp(x, 1)) guess = numpy.random.randint(-10, 10) dx = d_n(p, 1) if dx(x) != 0: try: expected = optimize.newton(p, guess, dx, maxiter=iter) except RuntimeError: # Doesn't return if approximation continue print ' Test {}/{}'.format(i+1, n), result = rootfinding.newton(p, guess, tol_iter, n=iter) test_it(expected, result, max_error) i += 1 # The secant method as isn't able to stop if the difference between the # guesses is less than tolerance, whereas scipy's does: # github.com/scipy/scipy/blob/v0.14.0/scipy/optimize/zeros.py#L45 # This (important) feature (and the tests) will soon be implemented print ' Secant... SKIP' print ' Bisection...' # Slow method iter = 10**2 i = 0 while i < n: p = sympy.lambdify(x, rp(x, 1)) try: expected = optimize.bisect(p, -10, 10, maxiter=iter) except RuntimeError: # Doesn't return if approximation continue except ValueError: # Sem raizes no intervalo (um coeff = 0) continue print ' Test {}/{}'.format(i+1, n), result = rootfinding.bisec(p, -10, 10, tol_iter, n=iter) test_it(expected, result, max_error) i += 1
def t_rootfinding(): print 'rootfinding...' def test_it(expected, result, max_error): diff = abs(expected - result) if diff < max_error: print 'OK' else: print 'FAIL' print ' Expected:', expected print ' Got:', result print ' Difference:', diff print ' Tolerance:', max_error def rp(x, k=1, min=-1, max=1): """Random polynomial of degree k at x""" coeffs = numpy.random.uniform(min, max, size=k + 1) return sum([coeffs[i] * x**i for i in xrange(len(coeffs))]) x = sympy.symbols('x') # Number of tests n = 4 # Maximum iterations iter = 10 # How much can the tests differ from the expected results? Adjust # according to the method and number of iterations. max_error = 10**-8 # For simplicity, test only for degree 1 polynomials with roots in a known # interval print ' Newton...' i = 0 while i < n: p = sympy.lambdify(x, rp(x, 1)) guess = numpy.random.randint(-10, 10) dx = d_n(p, 1) if dx(x) != 0: try: expected = optimize.newton(p, guess, dx, maxiter=iter) except RuntimeError: # Doesn't return if approximation continue print ' Test {}/{}'.format(i + 1, n), result = rootfinding.newton(p, guess, tol_iter, n=iter) test_it(expected, result, max_error) i += 1 # The secant method as isn't able to stop if the difference between the # guesses is less than tolerance, whereas scipy's does: # github.com/scipy/scipy/blob/v0.14.0/scipy/optimize/zeros.py#L45 # This (important) feature (and the tests) will soon be implemented print ' Secant... SKIP' print ' Bisection...' # Slow method iter = 10**2 i = 0 while i < n: p = sympy.lambdify(x, rp(x, 1)) try: expected = optimize.bisect(p, -10, 10, maxiter=iter) except RuntimeError: # Doesn't return if approximation continue except ValueError: # Sem raizes no intervalo (um coeff = 0) continue print ' Test {}/{}'.format(i + 1, n), result = rootfinding.bisec(p, -10, 10, tol_iter, n=iter) test_it(expected, result, max_error) i += 1