codexpast-exam-of-the-mathematics-course-of-the-university-of-cambridge2003iiipaper-12-kernels.py
past-exam-of-the-mathematics-course-of-the-university-of-cambridge/2003/iii/paper-12-kernels.py
"""Illustrate the three multigraph kernels of a connected excess-one graph.
Python 3.14.4, NumPy 2.3.5, Matplotlib 3.10.7+dfsg1.
Writes paper-12-kernels.png to caller CWD. Honors caller MPLCONFIGDIR.
"""
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
def main():
fig, axes = plt.subplots(1, 3, figsize=(10, 3.2), facecolor="white", layout="constrained")
edge_color = "#285f84"
node_color = "#bc5a23"
t = np.linspace(0, 2*np.pi, 200)
for ax in axes:
ax.set_aspect("equal")
ax.set_xlim(-1.6, 1.6)
ax.set_ylim(-1.35, 1)
ax.set_axis_off()
for center in [-.55, .55]:
axes[0].plot(center+.55*np.cos(t), .55*np.sin(t), color=edge_color, lw=2.4)
axes[0].scatter([0], [0], s=65, color=node_color, zorder=3)
axes[0].text(0, -1.1, "1 vertex · 2 loops\ndegree 4", ha="center", fontsize=11)
axes[0].set_title("Two-loop bouquet", fontsize=12)
s = np.linspace(0, 1, 160)
for height in [-.66, 0, .66]:
axes[1].plot(-.8+1.6*s, 4*height*s*(1-s), color=edge_color, lw=2.4)
axes[1].scatter([-.8, .8], [0, 0], s=65, color=node_color, zorder=3)
axes[1].text(0, -1.1, "2 vertices · 3 parallel edges\ndegrees 3, 3", ha="center", fontsize=11)
axes[1].set_title("Theta kernel", fontsize=12)
for center in [-1., 1.]:
axes[2].plot(center+.44*np.cos(t), .44*np.sin(t), color=edge_color, lw=2.4)
axes[2].plot([-.56, .56], [0, 0], color=edge_color, lw=2.4)
axes[2].scatter([-.56, .56], [0, 0], s=65, color=node_color, zorder=3)
axes[2].text(0, -1.1, "2 vertices · 2 loops + 1 bridge\ndegrees 3, 3", ha="center", fontsize=11)
axes[2].set_title("Dumbbell kernel", fontsize=12)
fig.suptitle("Bicyclic kernels: edges − vertices = 1", fontsize=14)
fig.savefig("paper-12-kernels.png", dpi=120, facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()