ZPOCC Example — Complex Polynomial Roots¶
This example uses nonlinearequations.polynomial_roots_complex()
(IMSL ZPOCC) to find all roots of two polynomials whose roots lie on
the complex unit circle:
Polynomial 1 — 5th roots of unity:
\[p(z) = z^5 - 1 = 0\]
Roots at angles \(0°, 72°, 144°, 216°, 288°\).
Polynomial 2 — roots at 45° offsets:
\[p(z) = z^4 + 1 = 0\]
Roots at angles \(45°, 135°, 225°, 315°\).
The backend uses NumPy’s companion-matrix eigenvalue method, which handles
complex coefficients natively. Coefficients are supplied in ascending
degree order: [a₀, a₁, …, aₙ].
Example Code¶
"""IMSL ZPOCC example: complex polynomial roots.
Demonstrates :func:`nonlinearequations.polynomial_roots_complex` (IMSL ZPOCC)
on two polynomials whose roots lie on the unit circle:
1. p(z) = z^5 - 1 (5th roots of unity)
2. p(z) = z^4 + 1 (roots at 45°, 135°, 225°, 315° on unit circle)
Outputs:
- Table printed to stdout
- SVG plot of roots on the complex plane with unit circle
- Saved to test_output/example_imsl_poly_roots_complex.svg
"""
from __future__ import annotations
from pathlib import Path
from typing import Dict
import matplotlib.pyplot as plt
import numpy as np
from nonlinearequations import polynomial_roots_complex
def run_demo_imsl_poly_roots_complex() -> Dict[str, object]:
"""Run IMSL ZPOCC example: complex polynomial roots on the unit circle.
Finds all roots of z^5 - 1 (5th roots of unity) and z^4 + 1 (rotated
4th roots) using the companion-matrix eigenvalue method, then plots them
on the complex plane together with the unit circle.
Args:
None
Returns:
Dict[str, object]: Result dict with keys ``roots_p1``
(np.ndarray), ``roots_p2`` (np.ndarray), ``fval1`` (float),
``fval2`` (float), and ``plot_path`` (str).
"""
# z^5 - 1: ascending coefficients [-1, 0, 0, 0, 0, 1]
coeffs_p1 = np.array([-1.0 + 0j, 0, 0, 0, 0, 1.0 + 0j])
# z^4 + 1: ascending coefficients [1, 0, 0, 0, 1]
coeffs_p2 = np.array([1.0 + 0j, 0, 0, 0, 1.0 + 0j])
result1 = polynomial_roots_complex(coeffs_p1)
result2 = polynomial_roots_complex(coeffs_p2)
roots1 = result1.x
roots2 = result2.x
print("\nIMSL ZPOCC Example: Complex Polynomial Roots")
print("-" * 65)
print("Polynomial 1: p(z) = z^5 - 1 (5th roots of unity)")
print(f" Max |p(root)| = {result1.fval:.2e} Converged: {result1.success}")
print(f" {'Root':<6} {'Real':>14} {'Imag':>14} {'Angle (deg)':>14}")
for z in sorted(roots1, key=lambda w: np.angle(w)):
deg = np.degrees(np.angle(z))
print(f" {'':6} {z.real:>14.8f} {z.imag:>14.8f} {deg:>14.4f}")
print()
print("Polynomial 2: p(z) = z^4 + 1 (roots at ±45° + ±135°)")
print(f" Max |p(root)| = {result2.fval:.2e} Converged: {result2.success}")
print(f" {'Root':<6} {'Real':>14} {'Imag':>14} {'Angle (deg)':>14}")
for z in sorted(roots2, key=lambda w: np.angle(w)):
deg = np.degrees(np.angle(z))
print(f" {'':6} {z.real:>14.8f} {z.imag:>14.8f} {deg:>14.4f}")
print("-" * 65)
# ------------------------------------------------------------------
# Plot: complex plane with unit circle and root markers
# ------------------------------------------------------------------
output_dir = Path("test_output")
output_dir.mkdir(parents=True, exist_ok=True)
plot_path = output_dir / "example_imsl_poly_roots_complex.svg"
theta = np.linspace(0, 2 * np.pi, 500)
unit_x = np.cos(theta)
unit_y = np.sin(theta)
fig, axes = plt.subplots(1, 2, figsize=(12, 5.5))
for ax, roots, title, poly_label, color in [
(axes[0], roots1, r"$z^5 - 1 = 0$ (5th roots of unity)", "p(z) = z⁵ − 1", "#0e7490"),
(axes[1], roots2, r"$z^4 + 1 = 0$ (roots at ±45°, ±135°)", "p(z) = z⁴ + 1", "#0891b2"),
]:
ax.plot(unit_x, unit_y, color="#aaaaaa", linewidth=1.2, linestyle="--", label="Unit circle")
ax.axhline(0, color="#cccccc", linewidth=0.7)
ax.axvline(0, color="#cccccc", linewidth=0.7)
ax.scatter(roots.real, roots.imag, color=color, s=120, zorder=5,
edgecolors="white", linewidths=0.8, label=f"Roots of {poly_label}")
for z in roots:
deg = np.degrees(np.angle(z))
ax.annotate(
f"{deg:.0f}°",
xy=(z.real, z.imag),
xytext=(z.real * 1.18, z.imag * 1.18),
fontsize=8,
ha="center",
va="center",
color=color,
)
ax.set_aspect("equal")
ax.set_xlim(-1.6, 1.6)
ax.set_ylim(-1.6, 1.6)
ax.set_xlabel("Re(z)")
ax.set_ylabel("Im(z)")
ax.set_title(title)
ax.legend(fontsize=8)
ax.grid(True, alpha=0.20)
fig.suptitle("IMSL ZPOCC: Complex Polynomial Roots on the Unit Circle", fontsize=13, fontweight="bold")
fig.tight_layout()
fig.savefig(plot_path, format="svg")
plt.close(fig)
return {
"roots_p1": roots1,
"roots_p2": roots2,
"fval1": result1.fval,
"fval2": result2.fval,
"plot_path": str(plot_path),
}
if __name__ == "__main__":
run_demo_imsl_poly_roots_complex()
Plot Output¶
Left: five roots of \(z^5 - 1\) equally spaced at 72° intervals. Right: four roots of \(z^4 + 1\) at 45° offsets. Grey dashed circle is the unit circle \(|z| = 1\).¶
Console Output¶
IMSL ZPOCC Example: Complex Polynomial Roots
-----------------------------------------------------------------
Polynomial 1: p(z) = z^5 - 1 (5th roots of unity)
Max |p(root)| = 3.27e-15 Converged: True
Root Real Imag Angle (deg)
-0.80901699 -0.58778525 -144.0000
0.30901699 -0.95105652 -72.0000
1.00000000 0.00000000 0.0000
0.30901699 0.95105652 72.0000
-0.80901699 0.58778525 144.0000
Polynomial 2: p(z) = z^4 + 1 (roots at ┬▒45┬░ + ┬▒135┬░)
Max |p(root)| = 1.68e-15 Converged: True
Root Real Imag Angle (deg)
-0.70710678 -0.70710678 -135.0000
0.70710678 -0.70710678 -45.0000
0.70710678 0.70710678 45.0000
-0.70710678 0.70710678 135.0000
-----------------------------------------------------------------