codexcategorical-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()