codexpast-exam-of-the-year-1-of-the-computer-science-course-of-the-university-of-oxford2015discrete-main-2015-euler-stability.py
past-exam-of-the-year-1-of-the-computer-science-course-of-the-university-of-oxford/2015/discrete-main-2015-euler-stability.py
"""Plot Question 5(b)'s exact and Euler decay curves; write PNG to CWD.
Tested with Python 3.14.4, matplotlib 3.10.7+dfsg1, numpy 2.3.5.
Dependencies are documented in the repository's top-level pyproject.toml.
Run: python /absolute/path/to/discrete-main-2015-euler-stability.py
"""
from pathlib import Path
import os
os.environ.setdefault('MPLCONFIGDIR', str(Path.cwd() / '.discrete-main-2015-matplotlib'))
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
def main():
plt.rcParams.update({'font.family': 'DejaVu Sans', 'font.size': 10})
decay_rate = 8.0
fig, axes = plt.subplots(1, 2, figsize=(10, 3.8), layout='constrained')
fig.set_facecolor('white')
t = np.linspace(0, 1, 401)
exact = 2 * np.exp(-decay_rate * t)
panels = [
('Unstable and neutral', [(3, '#c23b22'), (4, '#b07700')]),
('Stable: damped oscillation or monotone decay', [(5, '#8053a1'), (16, '#007d79')]),
]
for ax, (title, cases) in zip(axes, panels):
ax.set_facecolor('white')
ax.plot(t, exact, color='#202020', linewidth=2, label=r'Exact $2e^{-8t}$')
for steps, colour in cases:
grid = np.arange(steps + 1) / steps
factor = 1 - decay_rate / steps
values = 2 * factor ** np.arange(steps + 1)
ax.plot(grid, values, 'o-', markersize=4, color=colour,
label=f'N = {steps}, factor = {factor:.2f}')
ax.axhline(0, color='#777777', linewidth=0.6)
ax.set(xlim=(0, 1), xlabel='x', ylabel='y', title=title)
ax.grid(alpha=0.2)
ax.legend(fontsize=9, loc='best')
axes[0].set_ylim(-10, 6)
axes[1].set_ylim(-1.4, 2.3)
fig.suptitle('Forward Euler for exponential decay: stability requires N > 4', fontsize=13)
fig.savefig(Path.cwd() / 'discrete-main-2015-euler-stability.png', dpi=120,
facecolor='white', transparent=False, metadata={'Software': 'Matplotlib'})
plt.close(fig)
if __name__ == '__main__':
main()