codex/summation-loop-trace-and-stalled-variant.py

summation-loop-trace-and-stalled-variant.py
"""Draw a finite n=4 trace and an infinite stalled loop.

Tested with Python 3.14, matplotlib 3.10.7. Run from _media.
"""

from pathlib import Path

import matplotlib.pyplot as plt
from matplotlib.patches import FancyArrowPatch, FancyBboxPatch, Rectangle


def main():
    n, i, s = 4, 0, 0
    states = [(i, s, n - i)]
    while i < n:
        i = i + 1
        s = s + i
        states.append((i, s, n - i))
    assert states == [(0, 0, 4), (1, 1, 3), (2, 3, 2), (3, 6, 1), (4, 10, 0)]
    assert all(2 * acc == pos * (pos + 1) for pos, acc, _ in states)

    plt.rcParams.update({"font.family": "DejaVu Sans", "font.size": 12})
    fig, ax = plt.subplots(figsize=(11, 6.5), dpi=110, facecolor="white")
    fig.subplots_adjust(left=0.03, right=0.98, top=0.86, bottom=0.055)
    ax.set(xlim=(0, 11), ylim=(0, 6.4))
    ax.axis("off")
    ink, blue, green, orange = "#23334a", "#266ca0", "#21795f", "#bc641d"
    fig.suptitle("An invariant remembers; a variant proves progress", y=0.97,
                 fontsize=19, weight="bold", color=ink)
    fig.text(0.5, 0.9, "n = 4 • states shown just before each condition check • exact integers",
             ha="center", color=ink, fontsize=12)
    ax.axvline(7.05, ymin=0.04, ymax=0.98, color="#cbd1d9", lw=1)
    ax.text(0.1, 6.12, "Increment i, then add i", fontsize=15, weight="bold", color=blue)
    ax.text(7.45, 6.12, "Stalled body:  i = i", fontsize=15, weight="bold", color=orange)
    ax.text(0.1, 5.58, "i", weight="bold", ha="center", color=ink)
    ax.text(0.9, 5.58, "s", weight="bold", ha="center", color=ink)
    ax.text(2.3, 5.58, "V = 4 − i", weight="bold", color=ink)
    ax.text(5.9, 5.58, "i < 4 ?", weight="bold", color=ink, ha="center")

    for row, (pos, acc, variant) in enumerate(states):
        y = 4.95 - row * 0.87
        ax.add_patch(FancyBboxPatch((-0.13, y - 0.3), 6.85, 0.6,
                                   boxstyle="round,pad=0.04", linewidth=0,
                                   facecolor="#eaf6ef" if variant == 0 else "#eef6fd"))
        ax.text(0.1, y, str(pos), ha="center", va="center", fontsize=16, color=ink)
        ax.text(0.9, y, str(acc), ha="center", va="center", fontsize=16, color=ink)
        for k in range(variant):
            ax.add_patch(Rectangle((2.3 + 0.47 * k, y - 0.17), 0.35, 0.34,
                                   facecolor=blue, edgecolor="white"))
        ax.text(4.55, y, str(variant), ha="center", va="center", fontsize=16, color=blue)
        ax.text(5.9, y, "false → exit" if variant == 0 else "true", va="center",
                ha="center", color=green if variant == 0 else ink, fontsize=12)
        if row < n:
            ax.add_patch(FancyArrowPatch((1.55, y - 0.32), (1.55, y - 0.54),
                                        arrowstyle="-|>", mutation_scale=12, color=blue))
            ax.text(1.73, y - 0.435, f"+{pos + 1}", va="center", fontsize=11, color=blue)

    for y in (4.85, 3.48, 2.11):
        ax.add_patch(FancyBboxPatch((7.55, y - 0.37), 2.95, 0.74,
                                   boxstyle="round,pad=0.07", facecolor="#fff4e6",
                                   edgecolor=orange, linewidth=1.2))
        ax.text(9.025, y, "i = 0,  s = 0,  V = 4", ha="center", va="center", color=ink)
    for y in (4.4, 3.03):
        ax.add_patch(FancyArrowPatch((9.025, y), (9.025, y - 0.45),
                                    arrowstyle="-|>", mutation_scale=13, color=orange))
    ax.text(9.025, 1.24, "⋮", ha="center", va="center", fontsize=26, color=orange)
    ax.text(3.3, 0.63, "Four additions; return s = 10\n" + r"$2\cdot10=4\cdot5$",
            color=green, ha="center", va="center", fontsize=13, linespacing=1.6)
    ax.text(9.025, 0.5, "Equation stays true.\nCondition stays true. No exit.",
            color=orange, ha="center", va="center", linespacing=1.6)
    fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"), facecolor="white", transparent=False)
    plt.close(fig)


if __name__ == "__main__":
    main()