A root finding example

The test function is \(y = 5x^2+10x-8\). Newton’s method is implemented to find the root of the test function. The user should be able to find the root and access the Jacobian of each iteration.

First, we instantiate a Number(5) as the initial guess (\(x_0\)) of the root. The Newton() method takes the test function and the initial guess.

Second, the function and its derivative are evaluated at \(x_0\), then \(x_1\) is calculated as \(x_1 = x_0-\frac{f(x_0)}{f'(x_0)}\). The jacobian is stored in the jacobians list

Third, the evaluation of the function at \(x_1\) is compared with the threshhold, in this case \(10^{-7}\). The absolute value of the function’s value at \(x_1\) is larger than the threshold, so \(x_0\)‘s value is updated, i.e., \(x_0 = x_1\).

Fourth, the function and its derivative is again evaluated at the new \(x_0\). Derivative is stored in the jacobians list. This process is repeated until the threshold is met.

Fifth, the Newton() method returns the root and the jacobians list. User may access each step’s derivative from this list.

import sys
sys.path.append('..')

import autodiff.operations as operations
from autodiff.structures import Number
import numpy as np
from copy import deepcopy

def func(x):
    return 5 * x ** 2 + 10 * x - 8

def newtons_method(func, initial_guess):
    
    #stores a list of jacobians from each iteration
    jacobians = []
    
    x0 = initial_guess

    fxn = func(initial_guess)
    
    fpxn = fxn.jacobian(initial_guess)
    
    x1 = x0 - fxn/fpxn

    jacobians.append(fpxn)
    
    
    while abs(fxn.val) > 1e-7:
        x0 = x1

        fxn = func(x0)

        fpxn = fxn.jacobian(x0)

        jacobians.append(fpxn)
        
        x1 = x0- fxn / fpxn
        
    return x1, jacobians
    

x0 = Number(5)
xstar, jacobians = newtons_method(func, x0)

print(xstar, jacobians[-1])
Number(val=0.6124515496597099) 16.124515496597116