codexpast-exam-of-the-mathematics-course-of-the-year-2-of-the-natural-sciences-course-of-the-university-of-cambridge2020paper-1-q5-fence-minima.py
past-exam-of-the-mathematics-course-of-the-year-2-of-the-natural-sciences-course-of-the-university-of-cambridge/2020/paper-1-q5-fence-minima.py
"""Original solution sketches for the three fence minimizers.
Write the PNG basename in the current working directory. Tested with Python
3.14.4, matplotlib 3.10.7 and numpy 2.3.5; dependencies are declared in the
repository's top-level pyproject.toml.
"""
from pathlib import Path
from math import pi, sin, sinh
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
def bisect_increasing(function, left, right, target):
for _ in range(80):
midpoint = (left + right) / 2
if function(midpoint) < target:
left = midpoint
else:
right = midpoint
return (left + right) / 2
def main():
a, length = 1.0, 2.7
ratio = length / (2 * a)
angle = bisect_increasing(lambda t: t / sin(t), 1e-8, pi / 2, ratio)
radius = a / sin(angle)
q = bisect_increasing(lambda t: sinh(t) / t, 1e-8, 4.0, ratio)
scale = a / q
x = np.linspace(-a, a, 601)
y_a = x - a * np.sinh(x) / np.sinh(a)
y_b = np.sqrt(radius**2 - a**2) - np.sqrt(radius**2 - x**2)
y_c = scale * (np.cosh(x / scale) - np.cosh(a / scale))
fig, axes = plt.subplots(1, 3, figsize=(10.0, 3.75), layout="constrained")
fig.patch.set_facecolor("white")
titles = ["Company A: unconstrained length", "Company B: circular arc",
"Company C: catenary"]
formulas = [r"$y=x-a\sinh x/\sinh a$",
r"$L=2R\arcsin(a/R)$", r"$L=2b\sinh(a/b)$"]
for ax, y, title, formula in zip(axes, [y_a, y_b, y_c], titles, formulas):
ax.axhline(0, color="#888888", lw=0.9)
ax.plot(x / a, y / a, color="#2463a5", lw=2.4)
ax.plot([-1, 1], [0, 0], "o", color="black", ms=3.5)
ax.set(xlabel=r"$x/a$", ylabel=r"$y/a$", title=title, xlim=(-1.08, 1.08))
ax.set_xticks([-1, 0, 1])
ax.spines[["top", "right"]].set_visible(False)
ax.text(0.5, 0.04, formula, transform=ax.transAxes, ha="center", fontsize=10,
bbox={"facecolor": "white", "edgecolor": "none", "alpha": 0.9})
height = max(abs(y_a.min()), abs(y_a.max()))
axes[0].set_ylim(-1.35 * height, 1.35 * height)
for ax in axes[1:]:
ax.set_ylim(-1.0, 0.14)
fig.suptitle(r"Original minimizing-curve sketches: $a=1$; fixed length $L=2.7a$ for B and C",
fontsize=12)
fig.savefig(Path(__file__).with_suffix(".png").name, dpi=125, facecolor="white")
plt.close(fig)
if __name__ == "__main__":
main()