codex/categorical-composition-examples.py

categorical-composition-examples.py
"""Computed composition and singleton naturality; write the PNG to cwd."""

from pathlib import Path

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt


def arrow(ax, start, end, label, color, offset=(0, 0.12)):
    ax.annotate("", xy=end, xytext=start,
                arrowprops={"arrowstyle": "-|>", "lw": 2,
                            "color": color, "shrinkA": 28, "shrinkB": 28,
                            "mutation_scale": 18})
    midpoint = ((start[0] + end[0]) / 2, (start[1] + end[1]) / 2)
    ax.text(midpoint[0] + offset[0], midpoint[1] + offset[1], label,
            ha="center", va="center", fontsize=12, color=color,
            bbox={"facecolor": "white", "edgecolor": "none", "pad": 1})


def node(ax, location, label):
    ax.text(*location, label, ha="center", va="center", fontsize=15,
            bbox={"boxstyle": "round,pad=0.35", "fc": "#f1f5f8",
                  "ec": "#b6c1cc"}, zorder=5)


def main():
    f = lambda x: x + 1
    g = lambda x: 2 * x
    assert g(f(3)) == 8 and f(g(3)) == 7
    assert {f(x) for x in {3}} == {f(3)} == {4}
    fig, axes = plt.subplots(1, 2, figsize=(10.4, 4.9), dpi=120)
    blue, orange = "#176997", "#b95f22"
    for ax in axes:
        ax.set_xlim(-0.5, 2.5)
        ax.set_ylim(-0.7, 1.7)
        ax.axis("off")
    ax = axes[0]
    for y, values, maps, color in [
        (1.0, [3, 4, 8], ["f: add 1", "g: double"], blue),
        (0.0, [3, 6, 7], ["g: double", "f: add 1"], orange),
    ]:
        for x, value in enumerate(values):
            node(ax, (x, y), str(value))
        for x, label in enumerate(maps):
            arrow(ax, (x, y), (x + 1, y), label, color, (0, 0.3))
    ax.set_title("Composition can depend on order", fontsize=13, pad=14)
    ax.text(1, -0.5, r"$g\circ f=2x+2$     $f\circ g=2x+1$",
            ha="center", fontsize=13)
    ax = axes[1]
    a, b, c, d = (0, 1.05), (2, 1.05), (0, 0), (2, 0)
    for point, label in [(a, "3"), (b, "4"), (c, "{3}"), (d, "{4}")]:
        node(ax, point, label)
    arrow(ax, a, b, "f: add 1", blue, (0, 0.3))
    arrow(ax, c, d, r"$\mathcal{P}(f)$: take image", blue, (0, -0.32))
    arrow(ax, a, c, r"$\eta_X$", orange, (-0.22, 0))
    arrow(ax, b, d, r"$\eta_Y$", orange, (0.22, 0))
    ax.set_title("Naturality: both routes agree", fontsize=13, pad=14)
    ax.text(1, -0.6, r"$f(\{3\})=\{f(3)\}=\{4\}$", ha="center", fontsize=13)
    fig.suptitle("Arrow equations can be checked on actual inputs", fontsize=16)
    fig.subplots_adjust(left=0.025, right=0.975, top=0.8, bottom=0.08,
                        wspace=0.18)
    fig.savefig(Path.cwd() / Path(__file__).with_suffix(".png").name,
                facecolor="white")
    plt.close(fig)


if __name__ == "__main__":
    main()