codexcholesky-two-triangular-solves.py
cholesky-two-triangular-solves.py
"""Draw an exact Cholesky factorization and two solves; output PNG to CWD."""
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
def main():
a = np.array([[4, 2], [2, 5]])
lower = np.array([[2, 0], [1, 2]])
assert np.array_equal(lower @ lower.T, a)
assert np.array_equal(a @ np.array([1, 2]), np.array([8, 12]))
fig, ax = plt.subplots(figsize=(10.8, 5.8), dpi=120)
fig.patch.set_facecolor("white")
ax.set(xlim=(0, 10.8), ylim=(0, 5.8))
ax.axis("off")
ax.text(5.4, 5.48, "One factorization, two triangular solves", ha="center", fontsize=19, weight="bold")
def matrix(center, label, data):
ax.text(center, 4.93, label, ha="center", fontsize=19)
for row in range(2):
for col in range(2):
value = data[row, col]
ax.text(center+(col-.5)*.7, 4.31-row*.65, str(value), ha="center", va="center", fontsize=22, color="#26718b" if value else "#aaaaaa")
for x, sign in [(center-.73, 1), (center+.73, -1)]:
ax.plot([x+sign*.14, x, x, x+sign*.14], [4.68, 4.68, 3.27, 3.27], color="#222222", lw=1.7)
matrix(1.9, r"$A$", a)
matrix(5.35, r"$L$", lower)
matrix(8.75, r"$L^T$", lower.T)
ax.text(3.62, 3.97, "=", fontsize=25, ha="center", va="center")
ax.text(7.04, 3.97, "×", fontsize=25, ha="center", va="center")
ax.plot([.4, 10.4], [2.92, 2.92], color="#dddddd")
ax.text(.6, 2.54, r"Given $b=(8,12)^T$, first solve $Ly=b$:", fontsize=15)
ax.text(1.1, 1.98, r"$2y_1=8,\quad y_1+2y_2=12$", fontsize=17)
ax.text(7.1, 1.98, r"$y=(4,4)^T$", fontsize=17, color="#26718b")
ax.text(.6, 1.34, r"Then solve $L^Tx=y$:", fontsize=15)
ax.text(1.1, .81, r"$2x_2=4,\quad 2x_1+x_2=4$", fontsize=17)
ax.text(7.1, .81, r"$x=(1,2)^T$", fontsize=17, color="#26718b")
ax.text(5.4, .14, "Positive diagonal entries fix the signs of the triangular factor.", ha="center", fontsize=12)
fig.subplots_adjust(left=.01, right=.99, top=.99, bottom=.01)
fig.savefig(Path(__file__).stem + ".png", facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()