{
 "nbformat": 4,
 "nbformat_minor": 5,
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3"
  }
 },
 "cells": [
  {
   "cell_type": "code",
   "id": "cell-0",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": "# --- house style (the Press palette: accent/navy/gold/parchment) ---\nimport matplotlib as mpl\nACCENT, NAVY, GOLD, PARCH = '#7a1f1f', '#1f3a5f', '#b8860b', '#f7f2e7'\nmpl.rcParams.update({'figure.facecolor': PARCH, 'axes.facecolor': '#fffdf6',\n                     'axes.edgecolor': '#c9bfa3', 'font.family': 'serif'})\n\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom matplotlib import animation\n\nV = np.array([[i, j, k, l] for i in (0, 1, 2) for j in (0, 1, 2)\n                            for k in (0, 1, 2) for l in (0, 1, 2)], float) - 1.0\nsel = np.all(np.abs(V) > 0.5, axis=1)                 # the A^4 sub-tesseract (16 vertices)\nE = [(a, b) for a in range(81) for b in range(a + 1, 81)\n     if np.sum(np.abs(V[a] - V[b])) == 1.0]            # unit edges of the 4-grid\n\ndef project(P, th):\n    c, s = np.cos(th), np.sin(th)\n    R = np.eye(4); R[0, 0] = R[3, 3] = c; R[0, 3] = -s; R[3, 0] = s   # xw rotation\n    Q = P @ R.T\n    d = 2.5\n    return Q[:, :3] / (d - Q[:, 3])[:, None] * d       # 4D->3D perspective, then drop z\n\nfig = plt.figure(figsize=(10, 4))\nax1, ax2 = fig.add_subplot(121), fig.add_subplot(122)\nns = np.arange(1, 21)\nax2.plot(ns, (2/3)**ns, 'o-', color=ACCENT)\nax2.set(xlabel='rung n', ylabel='$|T|^n$',\n        title='Vanishing Tesseract: $(2/3)^n \\\\to 0$ (Cor. 7.7)')\n\ndef draw(th):\n    ax1.clear(); ax1.axis('off')\n    ax1.set(xlim=(-1.7, 1.7), ylim=(-1.7, 1.7), aspect='equal',\n            title='$\\\\sigma^4$: a tesseract of tesserae (Thm 7.6)')\n    P = project(V, th)\n    for a, b in E:\n        hot = sel[a] and sel[b]\n        ax1.plot([P[a, 0], P[b, 0]], [P[a, 1], P[b, 1]],\n                 color=ACCENT if hot else 'lightsteelblue', lw=2.0 if hot else 0.7)\n    ax1.scatter(P[sel, 0], P[sel, 1], c=ACCENT, s=18, zorder=3)\n\nani = animation.FuncAnimation(fig, draw, frames=np.linspace(0, np.pi, 120), interval=50)\n# Colab:  from IPython.display import HTML; HTML(ani.to_jshtml())\n# Web:    ani.save('py10_tesseract.gif', writer='pillow', fps=20)\nplt.show()\n"
  }
 ]
}