codexcayley-hamilton-matrix-power-reduction.py
cayley-hamilton-matrix-power-reduction.py
"""Illustrate original integer matrix powers reduced by Cayley–Hamilton; emit to CWD."""
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
def main():
a = np.array([[2, 1], [1, 1]], dtype=object)
identity = np.eye(2, dtype=object)
assert np.array_equal(a @ a - 3 * a + identity, np.zeros((2, 2), dtype=object))
rows = []
coefficient, constant = 0, 1
for n in range(8):
assert np.array_equal(np.linalg.matrix_power(a, n), coefficient * a + constant * identity)
rows.append([n, coefficient, constant])
coefficient, constant = 3 * coefficient + constant, -coefficient
fig = plt.figure(figsize=(10, 6), dpi=120, facecolor="white", layout="constrained")
grid = fig.add_gridspec(2, 3, height_ratios=[1.4, 1])
ax = fig.add_subplot(grid[0, :2])
ax.axis("off")
table = ax.table(cellText=rows, colLabels=["n", "Coefficient of A", "Coefficient of I"], cellLoc="center", bbox=[0.15, 0, 0.7, 0.9])
table.auto_set_font_size(False)
table.set_fontsize(11)
for j in range(3):
table[(0, j)].set_facecolor("#dce9f4")
table[(6, j)].set_facecolor("#e5f2e5")
ax.set_title(r"Every power is $A^n=a_n A+b_n I$", fontsize=14)
ax = fig.add_subplot(grid[0, 2])
ax.axis("off")
for y, text in [(0.91, "A = [[2, 1], [1, 1]]"), (0.68, r"$A^2=3A-I$"), (0.43, r"$a_{n+1}=3a_n+b_n$"), (0.24, r"$b_{n+1}=-a_n$")]:
ax.text(0.5, y, text, ha="center", va="center", fontsize=13)
matrices = [55 * a, -21 * identity, np.linalg.matrix_power(a, 5)]
for j, (matrix, title) in enumerate(zip(matrices, [r"$55A$", r"$-21I$", r"$A^5=55A-21I$"])):
ax = fig.add_subplot(grid[1, j])
values = np.asarray(matrix, dtype=float)
ax.imshow(values, cmap="RdBu", vmin=-110, vmax=110)
for (i, k), value in np.ndenumerate(matrix):
ax.text(k, i, str(value), ha="center", va="center", fontsize=17, color="white" if abs(value) > 70 else "black")
ax.set(xticks=[], yticks=[], title=title)
fig.suptitle("Two scalar coefficients replace repeated matrix multiplication", fontsize=15)
fig.savefig(Path(__file__).stem + ".png", facecolor="white")
plt.close(fig)
if __name__ == "__main__":
main()