codexcayley-hamilton-jordan-block-shear.py
cayley-hamilton-jordan-block-shear.py
"""Show why a repeated eigenvalue does not remove a nilpotent shear; emit to CWD."""
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
def main():
nilpotent = np.array([[0.0, 1.0], [0.0, 0.0]])
identity = np.eye(2)
matrix = 2 * identity + nilpotent
square = np.array([[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]], dtype=float)
fig, axes = plt.subplots(2, 2, figsize=(10, 5.8), dpi=120, facecolor="white", layout="constrained")
for ax, n in zip(axes.flat, [0, 1, 4, 8]):
transformed = identity + n / 2 * nilpotent
assert np.allclose(np.linalg.matrix_power(matrix, n) / 2**n, transformed)
points = square @ transformed.T
ax.fill(points[:, 0], points[:, 1], color="#b7d6f2", alpha=0.7)
ax.plot(points[:, 0], points[:, 1], color="#1565a8", lw=2)
ax.plot(square[:, 0], square[:, 1], "--", color="#777777", lw=1)
ax.annotate("", xy=(n / 2, 1), xytext=(0, 0), arrowprops={"arrowstyle": "->", "color": "#a44c1c", "lw": 2})
ax.set(xlim=(-0.3, 5.4), ylim=(-0.2, 1.4), xticks=range(6), yticks=[0, 1], title=f"n = {n}: top edge shifts by {n / 2:g}")
ax.set_aspect("equal", adjustable="box")
ax.grid(alpha=0.2)
fig.suptitle(r"$B=2I+N$, $N^2=0$: normalized powers $B^n/2^n=I+(n/2)N$", fontsize=15)
fig.supxlabel("Horizontal coordinate; dashed outline is the original unit square")
fig.supylabel("Vertical coordinate")
fig.savefig(Path(__file__).stem + ".png", facecolor="white")
plt.close(fig)
if __name__ == "__main__":
main()