codex/rational-addition-commuting-counterexample.py

rational-addition-commuting-counterexample.py
"""Draw correct addition and an invariant-preserving incorrect operation.

Tested with Python 3.14, matplotlib 3.10.7, numpy 2.3.5 (root pyproject.toml).
Run from _media; writes the matching PNG to the current directory.
"""

from fractions import Fraction
from pathlib import Path

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


def main():
    plt.rcParams.update({"font.family": "DejaVu Sans", "font.size": 12})
    fig, axes = plt.subplots(1, 2, figsize=(12, 5.8), dpi=120, facecolor="white")
    blue, green, red = "#245b93", "#24725b", "#a63535"
    expected = Fraction(1, 2) + Fraction(1, 3)
    assert expected == Fraction(5, 6)
    cases = [
        ("Correct addition", "F", (5, 6), green, True),
        ("Incorrect operation", "B", (2, 6), red, False),
    ]
    for ax, (title, operation, result, color, correct) in zip(axes, cases):
        ax.set(xlim=(0, 6), ylim=(0, 6))
        ax.axis("off")

        def node(x, y, label, width=1.8, height=0.72, tint=blue):
            ax.add_patch(FancyBboxPatch(
                (x - width / 2, y - height / 2), width, height,
                boxstyle="round,pad=0.04,rounding_size=0.10",
                edgecolor=tint, facecolor="white", linewidth=1.5,
            ))
            ax.text(x, y, label, ha="center", va="center", fontsize=14, color=tint)

        def arrow(start, end, label, text_xy, tint=blue):
            ax.add_patch(FancyArrowPatch(
                start, end, arrowstyle="-|>", mutation_scale=15,
                color=tint, linewidth=1.7,
            ))
            ax.text(*text_xy, label, ha="center", va="center", fontsize=13, color=tint)

        observed = Fraction(*result)
        assert (observed == expected) == correct
        assert result[1] != 0
        ax.text(3, 5.62, title, ha="center", fontsize=17, weight="bold", color=color)
        formula = (r"$F((a,b),(c,d))=(ad+bc,bd)$" if correct
                   else r"$B((a,b),(c,d))=(a+c,bd)$")
        ax.text(3, 5.10, formula, ha="center", fontsize=13, color=color)
        node(1.08, 4.12, "(1, 2)\n(1, 3)", height=0.94)
        node(4.80, 4.12, f"{result}", tint=color)
        arrow((2.05, 4.12), (3.82, 4.12), operation, (3.00, 4.39), color)
        node(1.08, 1.54, r"$(\frac{1}{2},\frac{1}{3})$", height=0.9, tint=green)
        node(4.80, 1.54, r"$\frac{5}{6}$", width=1.0, tint=green)
        arrow((1.08, 3.57), (1.08, 2.07), r"$\alpha\times\alpha$", (0.64, 2.83))
        arrow((2.05, 1.54), (4.19, 1.54), "abstract addition", (3.10, 1.12), green)
        if correct:
            arrow((4.80, 3.70), (4.80, 2.03), r"$\alpha$", (5.20, 2.85), green)
            ax.text(3, 0.48, "Both paths give 5/6", ha="center", color=green, fontsize=14)
        else:
            node(4.80, 2.85, r"$\frac{1}{3}$", width=1.0, tint=red)
            arrow((4.80, 3.70), (4.80, 3.20), r"$\alpha$", (5.35, 3.46), red)
            ax.text(4.80, 2.15, r"$\ne$", ha="center", va="center", color=red, fontsize=24)
            ax.text(3, 0.48, "Valid output; wrong abstract value", ha="center", color=red, fontsize=13)

    fig.suptitle("A nonzero denominator does not prove correct addition",
                 fontsize=18, weight="bold", y=0.99)
    fig.subplots_adjust(left=0.015, right=0.985, top=0.90, bottom=0.04, wspace=0.06)
    fig.savefig(Path(__file__).with_suffix(".png").name,
                facecolor="white", transparent=False)
    plt.close(fig)


if __name__ == "__main__":
    main()