codexkaratsuba-three-product-dataflow.py
karatsuba-three-product-dataflow.py
"""Draw the exact three-product trace; write a matching PNG in the CWD.
Tested with Python 3.14, matplotlib 3.10.7 and numpy 2.3.5.
"""
from pathlib import Path
import matplotlib.pyplot as plt
from matplotlib.patches import FancyArrowPatch, FancyBboxPatch
def main():
fig, ax = plt.subplots(figsize=(10.8, 6.6), dpi=110)
fig.patch.set_facecolor("white")
ax.set_facecolor("white")
ax.set(xlim=(0, 10), ylim=(0, 8))
ax.axis("off")
ink = "#24364b"
def box(x, y, w, h, label, color="#edf2f7", size=13):
ax.add_patch(FancyBboxPatch((x - w / 2, y - h / 2), w, h,
boxstyle="round,pad=0.09", facecolor=color,
edgecolor=ink, linewidth=1.2, zorder=2))
ax.text(x, y, label, ha="center", va="center", fontsize=size,
color=ink, linespacing=1.45, zorder=3)
def arrow(start, end, label=None, label_at=None):
ax.add_patch(FancyArrowPatch(start, end, arrowstyle="-|>",
mutation_scale=14, color=ink, linewidth=1.35, zorder=1))
if label:
ax.text(*label_at, label, ha="center", va="center", fontsize=11,
color=ink, bbox={"facecolor": "white", "edgecolor": "none", "pad": 2})
ax.text(5, 7.65, "Karatsuba: recover both cross terms with one product",
ha="center", fontsize=17, color=ink, weight="bold")
ax.text(5, 7.12, r"$x=12\cdot100+34,\quad y=56\cdot100+78,\quad q=100$",
ha="center", fontsize=15, color=ink)
ax.text(5, 6.52, "Three product calls (recursion or a small-input base case)",
ha="center", fontsize=12, color=ink)
box(1.7, 5.45, 2.35, 1.2, r"$p_2=ac$" + "\n" + r"$12\cdot56=672$", "#dceefa")
box(5, 5.45, 2.65, 1.2, r"$p_s=(a+b)(c+d)$" + "\n" + r"$46\cdot134=6164$", "#fcebc8")
box(8.3, 5.45, 2.35, 1.2, r"$p_0=bd$" + "\n" + r"$34\cdot78=2652$", "#ddf2e3")
box(5, 3.3, 4.25, 1.2,
"$h=p_s-p_2-p_0=ad+bc$\n$6164-672-2652=2840$")
arrow((5, 4.76), (5, 4.0))
arrow((2.65, 4.76), (3.65, 4.0), "$-p_2$", (2.82, 4.30))
arrow((7.35, 4.76), (6.35, 4.0), "$-p_0$", (7.18, 4.30))
box(5, 1.2, 7.1, 1.25,
r"$xy=p_2q^2+hq+p_0$" + "\n" + r"$6\,720\,000+284\,000+2652=7\,006\,652$", size=14)
arrow((5, 2.6), (5, 1.91), r"$\times q$", (5.6, 2.23))
arrow((1.7, 4.76), (1.7, 1.91), r"$\times q^2$", (1.13, 3.30))
arrow((8.3, 4.76), (8.3, 1.91), "$p_0$", (8.85, 3.30))
ax.text(5, 0.16, "Shift and add exact integer values; normalize carries when storing digits.",
ha="center", fontsize=12, color=ink)
fig.subplots_adjust(left=0.025, right=0.975, bottom=0.035, top=0.98)
fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"), facecolor="white",
transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()