codexpast-exam-of-the-mathematics-course-of-the-university-of-cambridge2026iapaper-2-gradient-flow.py
past-exam-of-the-mathematics-course-of-the-university-of-cambridge/2026/ia/paper-2-gradient-flow.py
#!/usr/bin/env python3
"""Generate paper-2-gradient-flow.png."""
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
def potential(x, y):
return x**3 - 3 * x + (x + 1) * y**2
def velocity(point):
x, y = point
return np.array((-(3 * x**2 - 3 + y**2), -2 * y * (x + 1)))
def rk4(point, step):
k1 = velocity(point)
k2 = velocity(point + step * k1 / 2)
k3 = velocity(point + step * k2 / 2)
k4 = velocity(point + step * k3)
return point + step * (k1 + 2 * k2 + 2 * k3 + k4) / 6
x = np.linspace(-1.75, 2.35, 420)
y = np.linspace(-1.7, 1.7, 360)
xx, yy = np.meshgrid(x, y)
uu = -(3 * xx**2 - 3 + yy**2)
vv = -2 * yy * (xx + 1)
zz = potential(xx, yy)
trajectory = [np.array((2.0, 1.0))]
for _ in range(900):
trajectory.append(rk4(trajectory[-1], 0.004))
trajectory = np.asarray(trajectory)
fig, ax = plt.subplots(figsize=(8.0, 6.0), layout="constrained")
levels = np.array([-4, -3, -2.4, -2.1, -2.01, -1.8, -1, 0, 1, 2, 4, 7, 11])
contours = ax.contour(xx, yy, zz, levels=levels, colors="0.55", linewidths=0.8)
ax.clabel(contours, fontsize=7, inline=True)
speed = np.hypot(uu, vv)
ax.streamplot(x, y, uu, vv, color=np.log1p(speed), cmap="Blues", density=1.15, linewidth=0.8, arrowsize=0.8)
ax.plot(trajectory[:, 0], trajectory[:, 1], color="#d62728", linewidth=2.7, label="trajectory from $(2,1)$")
ax.scatter([1, -1], [0, 0], s=55, c=["black", "#ff7f0e"], zorder=5)
ax.annotate("minimum $(1,0)$", (1, 0), (1.16, -0.28), arrowprops={"arrowstyle": "->"})
ax.annotate("degenerate critical point $(-1,0)$", (-1, 0), (-1.62, 0.38), arrowprops={"arrowstyle": "->"})
ax.scatter([2], [1], marker="*", s=130, color="#d62728", zorder=6)
ax.set(xlabel="$x$", ylabel="$y$", xlim=(x.min(), x.max()), ylim=(y.min(), y.max()), title="Contours of $U$ and the descending gradient flow $\\dot x=-U_x$, $\\dot y=-U_y$")
ax.set_aspect("equal")
ax.legend(loc="lower right")
fig.savefig(Path(Path(__file__).stem + ".png"), dpi=100, facecolor="white")
plt.close(fig)