Root Finding and Fixed-Point Iteration
Root Finding: Where Optimization Meets Equations
Finding where is closely related to
optimization: the first-order optimality condition
is itself a root-finding problem. SciPy provides fsolve, root,
and brentq for different scenarios. Fixed-point iteration
is a complementary framework
that appears in iterative algorithms throughout scientific computing.
Definition: Root-Finding Problem
Root-Finding Problem
Given , find such that:
For , this is finding the zeros of a scalar function. For , this is solving a system of nonlinear equations.
from scipy.optimize import fsolve, root, brentq
# Scalar: brentq (bracketing, guaranteed for continuous f)
x_star = brentq(f, a, b) # f(a) and f(b) must have opposite signs
# System: fsolve (Levenberg-Marquardt)
x_star = fsolve(func, x0)
# System: root (multiple methods)
result = root(func, x0, method='hybr')
Definition: Bisection Method
Bisection Method
For a continuous with (sign change), the bisection method repeatedly halves the interval:
- Compute
- If , set ; else set
- Repeat until
Convergence is linear with rate : error halves each iteration. After iterations, .
from scipy.optimize import brentq
# brentq combines bisection with inverse quadratic interpolation
x = brentq(f, a, b, xtol=1e-12)
brentq is guaranteed to converge for continuous functions and is
the most robust scalar root-finder in SciPy.
Bisection needs a bracket where changes sign.
For finding brackets automatically, use scipy.optimize.brentq
with a manual search or scipy.optimize.ridder.
Definition: Newton's Method for Root Finding
Newton's Method for Root Finding
For solving , Newton's method linearizes at :
For systems :
where is the Jacobian matrix .
Convergence is quadratic near the root (digits of accuracy double each iteration), but the method can diverge from poor starting points.
from scipy.optimize import newton
# Scalar with derivative
x = newton(f, x0, fprime=df)
# System: use root with method='hybr' (Powell's hybrid)
res = root(func, x0, jac=jacobian, method='hybr')
Definition: Fixed-Point Iteration
Fixed-Point Iteration
A fixed point of is a point where .
The iteration converges to if is a contraction: with .
from scipy.optimize import fixed_point
# Solve x = cos(x)
x_star = fixed_point(np.cos, 0.5)
# x_star β 0.7390851332 (Dottie number)
Root finding is equivalent to fixed-point iteration with for suitable .
Definition: Anderson Acceleration (Anderson Mixing)
Anderson Acceleration (Anderson Mixing)
Anderson acceleration speeds up fixed-point iteration by combining the last iterates:
where the weights are chosen to minimize the residual norm in a least-squares sense.
from scipy.optimize import root
# Anderson acceleration via root
def residual(x):
return g(x) - x # fixed point <=> root of residual
res = root(residual, x0, method='anderson')
Anderson acceleration is particularly effective for self-consistent field (SCF) iterations in electronic structure calculations and for ADMM in optimization.
Theorem: Banach Fixed-Point Theorem (Contraction Mapping)
If is a contraction on a complete metric space with Lipschitz constant :
then has a unique fixed point , and the iteration converges to from any starting point with:
A contraction shrinks distances. Repeated application of a shrinking map must converge to a unique fixed point β like repeatedly photocopying a photocopy, which converges to a single gray blob regardless of the original image.
Existence via Cauchy sequence
. The geometric series converges since , so is Cauchy and converges in the complete space.
Uniqueness
If are both fixed points: . Since , this implies .
Theorem: Local Quadratic Convergence of Newton's Method
If is twice continuously differentiable, , , and is sufficiently close to , then Newton's method converges quadratically:
where . The number of correct digits approximately doubles each iteration.
Newton's method replaces by its tangent line and finds where the tangent crosses zero. Near the root, the tangent is an excellent approximation, so each step makes the error roughly quadratic.
Example: Solving a Nonlinear System with fsolve
Find the intersection of and using
scipy.optimize.fsolve.
Implementation
import numpy as np
from scipy.optimize import fsolve
def equations(vars):
x, y = vars
return [x**2 + y**2 - 4, x*y - 1]
def jacobian(vars):
x, y = vars
return [[2*x, 2*y], [y, x]]
# Multiple starting points to find all roots
starts = [(1, 1), (-1, -1), (1, -1), (-1, 1)]
roots = set()
for x0 in starts:
sol = fsolve(equations, x0, fprime=jacobian, full_output=True)
if sol[2] == 1: # converged
root = tuple(np.round(sol[0], 10))
roots.add(root)
for r in sorted(roots):
print(f"Root: x={r[0]:.6f}, y={r[1]:.6f}")
Verification
Four solutions exist (two pairs of sign reflections): and . Each satisfies both and .
Example: Fixed-Point Iteration for Square Root
Compute using the fixed-point iteration (Babylonian method / Heron's method).
Implementation
import numpy as np
def sqrt_iteration(a, x0=1.0, tol=1e-15, max_iter=100):
x = x0
for k in range(max_iter):
x_new = 0.5 * (x + a / x)
if abs(x_new - x) < tol:
print(f"Converged in {k+1} iterations")
return x_new
x = x_new
return x
print(f"sqrt(2) = {sqrt_iteration(2):.15f}")
print(f"np ref = {np.sqrt(2):.15f}")
Analysis
This is Newton's method applied to . The iteration has . At , , giving quadratic convergence. Typically converges to machine precision in ~5 iterations.
Root-Finding Methods Compared
Compare bisection, Newton's method, and secant method on scalar root-finding problems.
Parameters
Root Finding and Fixed-Point Iteration
# Code from: ch08/python/root_finding.py
# Load from backend supplements endpointQuick Check
Which root-finding method is guaranteed to converge for a continuous function with a sign change on [a, b]?
Newton's method
Secant method
Bisection (brentq)
Fixed-point iteration
Bisection is guaranteed by the intermediate value theorem: if f(a)f(b) < 0 and f is continuous, there must be a root in [a,b].
Common Mistake: fsolve Silently Returns Non-Solution
Mistake:
Using fsolve(f, x0) and assuming the returned value is a root.
By default, fsolve does not raise an error if it fails to converge.
Correction:
Always check the convergence flag:
x, info, ier, msg = fsolve(f, x0, full_output=True)
if ier != 1:
print(f"WARNING: {msg}")
Or use root which returns a result.success boolean.
Key Takeaway
For scalar roots, use brentq; for systems, use root.
brentq is guaranteed to converge for bracketed continuous functions.
For systems, root(method='hybr') is the default workhorse.
Always provide the Jacobian when available for faster convergence,
and always check result.success.
Historical Note: Newton-Raphson Method
1660sIsaac Newton described his method for root-finding in De analysi
(1669), but only for polynomial equations. Joseph Raphson
independently published the general form in 1690. Thomas Simpson
generalized it to systems of equations in 1740. The method remains
the foundation of most modern nonlinear solvers, including
SciPy's fsolve (which uses a modified Powell hybrid method
combining Newton steps with dogleg trust regions).
Fixed Point
A point where . Solving is equivalent to finding a fixed point of .
Contraction Mapping
A function with Lipschitz constant : . The Banach theorem guarantees convergence of iteration .
Related: Fixed Point