from numpy import *
from scipy import linalg
from scipy.linalg import norm
from matplotlib.pyplot import *
from prettytable import PrettyTable
from timeit import default_timer as timer
import sys
sys.path.append('fncbook/')
import fncbook as FNC
# This (optional) block is for improving the display of plots.
# from IPython.display import set_matplotlib_formats
# set_matplotlib_formats("svg","pdf")
# %config InlineBackend.figure_format = 'svg'
rcParams["figure.figsize"] = [7, 4]
rcParams["lines.linewidth"] = 2
rcParams["lines.markersize"] = 4
rcParams['animation.html'] = "jshtml" # or try "html5"
Newton’s method is the cornerstone of rootfinding. We introduce the key idea with an example in Example 4.3.1.
Using general notation, if we have a root approximation xk, we can construct a linear model of f(x) using the classic formula for the tangent line of a differentiable function,
The graphs of Example 4.3.1 suggest why the Newton iteration may converge to a root: any differentiable function looks more and more like its tangent line as we zoom in to the point of tangency. Yet it is far from clear that it must converge, or at what rate it will do so. The matter of the convergence rate is fairly straightforward to resolve. Define the error sequence
The series in the denominator is of the form 1/(1+z). Provided ∣z∣<1, this is the limit of the geometric series 1−z+z2−z3+⋯. Keeping only the lowest-order terms, we derive
Recall that linear convergence is identifiable by trending toward a straight line on a log-linear plot of the error. When the convergence is quadratic, no such straight line exists—the convergence keeps getting steeper. As a numerical test, note that ∣ϵk+1∣≈K∣ϵk∣2 implies that as k→∞,
Let’s summarize the assumptions made to derive quadratic convergence as given by (4.3.7):
The residual function f has to have enough continuous derivatives to make the Taylor series expansion valid. Often this is stated as f having sufficient smoothness. This is usually not a problem, but see Exercise 4.3.6.
We required f′(r)=0, meaning that r must be a simple root. See Exercise 4.3.7 to investigate what happens at a multiple root.
We assumed that the sequence converged, which is not easy to guarantee in any particular case. In fact,
finding a starting value from which the Newton iteration converges is often the most challenging part of a rootfinding problem. We will try to deal with this issue in Quasi-Newton methods.
Our implementation of Newton’s iteration is given in Function 4.3.1. It accepts functions that evaluate f and f′ and the starting value x1 as input arguments. Beginning programmers are tempted to embed f and f′ directly into the code, but there are two good reasons not to do so. First, each new rootfinding problem would require its own copy of the code, creating a lot of duplication. Second, you may want to try more than one rootfinding algorithm for a particular problem, and keeping the definition of the problem separate from the algorithm for its solution makes this task much easier.
Function 4.3.1 also deals with a thorny practical issue: how to stop the iteration. It adopts a three-part criterion. First, it monitors the difference between successive root estimates, ∣xk−xk−1∣, which is used as a stand-in for the unknown error ∣xk−r∣. In addition, it monitors the residual ∣f(xk)∣, which is equivalent to the backward error and more realistic to control in badly conditioned problems (see The rootfinding problem). If either of these quantities is considered to be sufficiently small, the iteration ends. Finally, we need to protect against the possibility of a nonconvergent iteration, so the procedure terminates with a warning if a maximum number of iterations is exceeded.