ZBREN Example — Brent’s Method for Scalar Root Finding¶
This example uses nonlinearequations.zero_brent() (IMSL ZBREN) to
locate roots of two classic test functions using Brent’s bracketing method:
Problem 1 — cubic polynomial:
\[f(x) = x^3 - 2x - 5, \quad x \in [2, 3]\]
Root: \(x^* \approx 2.0946\).
Problem 2 — cosine fixed-point equation (Dottie number):
\[f(x) = \cos(x) - x, \quad x \in [0, 1]\]
Root: \(x^* \approx 0.7391\).
Brent’s method combines bisection, secant, and inverse-quadratic interpolation to guarantee convergence whenever a sign change is bracketed, achieving near-quadratic speed in smooth regions.
Example Code¶
"""IMSL ZBREN example: Brent's method for scalar root finding.
Demonstrates :func:`nonlinearequations.zero_brent` (IMSL ZBREN) on two
classic test cases:
1. f(x) = x^3 - 2x - 5 on [2, 3] (root ≈ 2.0946)
2. f(x) = cos(x) - x on [0, 1] (Dottie number ≈ 0.7391)
Outputs:
- Table printed to stdout
- SVG plot of both function curves with roots marked
- Saved to test_output/example_imsl_zbren.svg
"""
from __future__ import annotations
import math
from pathlib import Path
from typing import Dict
import matplotlib.pyplot as plt
import numpy as np
from nonlinearequations import zero_brent
def run_demo_imsl_zbren() -> Dict[str, object]:
"""Run IMSL ZBREN example: Brent's method for two scalar root problems.
Finds a root of x^3 - 2x - 5 on [2, 3] and a root of cos(x) - x on
[0, 1] using Brent's bracketing method.
Args:
None
Returns:
Dict[str, object]: Result dict with keys ``root1`` (float),
``root2`` (float), ``n_fev1`` (int), ``n_fev2`` (int), and
``plot_path`` (str).
"""
def f1(x: float) -> float:
"""Cubic polynomial f(x) = x^3 - 2x - 5.
Args:
x (float): Input value.
Returns:
float: f(x).
"""
return x**3 - 2.0 * x - 5.0
def f2(x: float) -> float:
"""Fixed-point equation f(x) = cos(x) - x.
Args:
x (float): Input value.
Returns:
float: f(x).
"""
return math.cos(x) - x
result1 = zero_brent(f1, 2.0, 3.0)
result2 = zero_brent(f2, 0.0, 1.0)
root1 = float(result1.x[0])
root2 = float(result2.x[0])
print("\nIMSL ZBREN Example: Brent's Method for Scalar Root Finding")
print("-" * 60)
print(f"{'Parameter':<35} {'Value':>20}")
print("-" * 60)
print("Problem 1: f(x) = x^3 - 2x - 5 on [2, 3]")
print(f"{' Root':<35} {root1:>20.10f}")
print(f"{' |f(root)|':<35} {result1.fval:>20.2e}")
print(f"{' Function evals':<35} {result1.n_fev:>20}")
print(f"{' Converged':<35} {str(result1.success):>20}")
print()
print("Problem 2: f(x) = cos(x) - x on [0, 1]")
print(f"{' Root (Dottie number)':<35} {root2:>20.10f}")
print(f"{' |f(root)|':<35} {result2.fval:>20.2e}")
print(f"{' Function evals':<35} {result2.n_fev:>20}")
print(f"{' Converged':<35} {str(result2.success):>20}")
print("-" * 60)
# ------------------------------------------------------------------
# Plot: two subplots, one per problem
# ------------------------------------------------------------------
output_dir = Path("test_output")
output_dir.mkdir(parents=True, exist_ok=True)
plot_path = output_dir / "example_imsl_zbren.svg"
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
# ── Panel 1: cubic polynomial ──────────────────────────────────────
x1 = np.linspace(1.5, 3.5, 400)
y1 = x1**3 - 2.0 * x1 - 5.0
ax1 = axes[0]
ax1.plot(x1, y1, color="#0e7490", linewidth=2.0, label=r"$f(x) = x^3 - 2x - 5$")
ax1.axhline(0, color="#888888", linewidth=0.8, linestyle="--")
ax1.axvspan(2.0, 3.0, alpha=0.08, color="#0e7490", label="Search bracket [2, 3]")
ax1.scatter([root1], [0.0], color="#d62728", s=100, zorder=5, label=f"Root ≈ {root1:.6f}")
ax1.set_xlabel("x")
ax1.set_ylabel("f(x)")
ax1.set_title("Brent: cubic polynomial")
ax1.legend(fontsize=8)
ax1.grid(True, alpha=0.25)
# ── Panel 2: cos(x) - x ───────────────────────────────────────────
x2 = np.linspace(-0.2, 1.4, 400)
y2 = np.cos(x2) - x2
ax2 = axes[1]
ax2.plot(x2, y2, color="#0891b2", linewidth=2.0, label=r"$f(x) = \cos(x) - x$")
ax2.axhline(0, color="#888888", linewidth=0.8, linestyle="--")
ax2.axvspan(0.0, 1.0, alpha=0.08, color="#0891b2", label="Search bracket [0, 1]")
ax2.scatter([root2], [0.0], color="#d62728", s=100, zorder=5, label=f"Root ≈ {root2:.6f}")
ax2.set_xlabel("x")
ax2.set_ylabel("f(x)")
ax2.set_title("Brent: cos(x) − x (Dottie number)")
ax2.legend(fontsize=8)
ax2.grid(True, alpha=0.25)
fig.suptitle("IMSL ZBREN: Brent's Method", fontsize=13, fontweight="bold")
fig.tight_layout()
fig.savefig(plot_path, format="svg")
plt.close(fig)
return {
"root1": root1,
"root2": root2,
"n_fev1": result1.n_fev,
"n_fev2": result2.n_fev,
"plot_path": str(plot_path),
}
if __name__ == "__main__":
run_demo_imsl_zbren()
Plot Output¶
Left: cubic \(x^3 - 2x - 5\) on the bracket \([2,3]\). Right: \(\cos(x) - x\) on \([0,1]\). Both roots are marked with red dots; the shaded regions indicate the search brackets.¶
Console Output¶
IMSL ZBREN Example: Brent's Method for Scalar Root Finding
------------------------------------------------------------
Parameter Value
------------------------------------------------------------
Problem 1: f(x) = x^3 - 2x - 5 on [2, 3]
Root 2.0945514815
|f(root)| 3.55e-15
Function evals 10
Converged True
Problem 2: f(x) = cos(x) - x on [0, 1]
Root (Dottie number) 0.7390851346
|f(root)| 2.26e-09
Function evals 9
Converged True
------------------------------------------------------------