codexmatrix-rank-reduction-consistency.py
matrix-rank-reduction-consistency.py
"""Draw an original exact row-reduction ledger; Python 3.14, Matplotlib 3.10."""
from pathlib import Path
import matplotlib.pyplot as plt
from matplotlib.patches import FancyBboxPatch, Rectangle
def matrix(ax, rows, left, bottom, width, height, pivots=(), separators=()):
"""Typeset a matrix without copying a textbook illustration."""
nrows, ncols = len(rows), len(rows[0])
dx, dy = width / ncols, height / nrows
for i, row in enumerate(rows):
for j, value in enumerate(row):
x, y = left + (j + 0.5) * dx, bottom + height - (i + 0.5) * dy
if (i, j) in pivots:
ax.add_patch(FancyBboxPatch((x - 0.022, y - 0.023), 0.044, 0.046,
boxstyle="round,pad=0.003", facecolor="#dcefe7",
edgecolor="#238452", linewidth=1.5))
ax.text(x, y, str(value), ha="center", va="center", fontsize=19)
for x, sign in [(left - 0.006, 1), (left + width + 0.006, -1)]:
ax.plot([x + sign * 0.008, x, x, x + sign * 0.008],
[bottom, bottom, bottom + height, bottom + height], color="#333333", linewidth=1.3)
for j in separators:
ax.plot([left + j * dx] * 2, [bottom, bottom + height], color="#555555", linewidth=1.1)
def main():
plt.rcParams.update({"font.size": 12, "font.family": "DejaVu Sans"})
fig, ax = plt.subplots(figsize=(11.2, 7), dpi=100, facecolor="white")
fig.subplots_adjust(left=0.015, right=0.985, bottom=0.025, top=0.98)
ax.set(xlim=(0, 1), ylim=(0, 1))
ax.axis("off")
ax.text(0.5, 0.963, "Two pivots, one invisible input direction", ha="center", fontsize=20)
for x, text in [(0.15, r"$A$"), (0.49, "Eliminate below first pivot"), (0.85, "Coefficient RREF")]:
ax.text(x, 0.882, text, ha="center", fontsize=14)
matrix(ax, [[1, 2, 3], [2, 4, 6], [1, 1, 2]], 0.058, 0.65, 0.184, 0.18)
matrix(ax, [[1, 2, 3], [0, 0, 0], [0, -1, -1]], 0.398, 0.65, 0.184, 0.18)
matrix(ax, [[1, 0, 1], [0, 1, 1], [0, 0, 0]], 0.758, 0.65, 0.184, 0.18,
pivots=((0, 0), (1, 1)))
for start, end in [(0.263, 0.374), (0.603, 0.734)]:
ax.annotate("", (end, 0.74), (start, 0.74), arrowprops={"arrowstyle": "->", "lw": 1.6})
ax.text(0.32, 0.622, r"$R_2\leftarrow R_2-2R_1$" + "\n" + r"$R_3\leftarrow R_3-R_1$",
ha="center", va="top", fontsize=12)
ax.text(0.67, 0.622, r"$R_2\leftrightarrow R_3$" + "\n" + r"$R_2\leftarrow -R_2$" + "\n" +
r"$R_1\leftarrow R_1-2R_2$", ha="center", va="top", fontsize=12)
ax.plot([0.035, 0.965], [0.49, 0.49], color="#dddddd", linewidth=1)
ax.text(0.25, 0.456, "Apply the same operations to both right-hand sides", ha="center", fontsize=13)
ax.text(0.105, 0.410, "After operations", ha="center", fontsize=12)
ax.text(0.405, 0.415, r"$b$", ha="center", color="#238452", fontsize=15)
ax.text(0.475, 0.415, r"$b'$", ha="center", color="#c53636", fontsize=15)
matrix(ax, [[1, 0, 1, -1, -1], [0, 1, 1, 1, 1], [0, 0, 0, 0, 1]],
0.16, 0.20, 0.35, 0.18, pivots=((0, 0), (1, 1)), separators=(3, 4))
ax.add_patch(Rectangle((0.37, 0.205), 0.14, 0.05, facecolor="none", edgecolor="#c53636", linewidth=1.5))
ax.text(0.335, 0.146, r"$b$: $0=0$" + " " + r"$b'$: $0=1$", ha="center", fontsize=15)
ax.text(0.335, 0.09, "Attainable Inconsistent", ha="center", fontsize=12)
ax.add_patch(FancyBboxPatch((0.60, 0.08), 0.345, 0.35, boxstyle="round,pad=0.015",
facecolor="#f3f7fa", edgecolor="#c4d5df"))
ax.text(0.773, 0.385, r"$x_1+x_3=0,\quad x_2+x_3=0$", ha="center", fontsize=15)
ax.text(0.773, 0.32, r"$\ker A=\mathrm{span}\{(-1,-1,1)^T\}$", ha="center", fontsize=14)
ax.text(0.773, 0.25, r"$Ax=b:\quad x=(-1,1,0)^T$", ha="center", fontsize=14)
ax.text(0.773, 0.20, r"$+\ t(-1,-1,1)^T$", ha="center", fontsize=14)
ax.text(0.773, 0.13, "Rank 2 + nullity 1 = 3 input coordinates", ha="center", fontsize=11)
fig.savefig(Path(__file__).with_suffix(".png").name, facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()