fig, axes = plt.subplots(1, 2, figsize=(11, 5))
# Stable node: Example 4.33
A433 = np.array([[-2., 2.], [2., -5.]])
lim = 3.0
x_g, y_g = np.meshgrid(np.linspace(-lim, lim, 22), np.linspace(-lim, lim, 22))
dx = A433[0,0]*x_g + A433[0,1]*y_g
dy = A433[1,0]*x_g + A433[1,1]*y_g
nrm = np.sqrt(dx**2 + dy**2 + 1e-10)
axes[0].quiver(x_g, y_g, dx/nrm, dy/nrm, alpha=0.3, color='gray', scale=28)
np.random.seed(7)
for _ in range(16):
r = lim * (0.3 + 0.7*np.random.rand())
theta = np.random.uniform(0, 2*np.pi)
x0 = [r*np.cos(theta), r*np.sin(theta)]
sol = solve_ivp(lambda t, y: A433 @ y, (0, 4), x0,
dense_output=True, max_step=0.05)
xy = sol.y; mask = np.all(np.abs(xy) < lim*1.4, axis=0)
axes[0].plot(xy[0, mask], xy[1, mask], 'steelblue', lw=1.2, alpha=0.7)
# Mark eigenvectors
evals433, evecs433 = np.linalg.eig(A433)
for i, color in enumerate(['crimson', 'darkorange']):
v = evecs433[:, i].real; v /= np.linalg.norm(v)
lam = evals433[i].real
for s in [1, -1]:
axes[0].annotate('', xy=(s*lim*0.8*v[0], s*lim*0.8*v[1]),
xytext=(0, 0),
arrowprops=dict(arrowstyle='->', color=color, lw=2.5))
axes[0].plot([], [], color=color, lw=2,
label=rf'$\lambda={lam:.0f}$, $\mathbf{{v}}=({v[0]:.2f},{v[1]:.2f})$')
axes[0].axhline(0, color='k', lw=0.5); axes[0].axvline(0, color='k', lw=0.5)
axes[0].plot(0, 0, 'ko', markersize=7, zorder=5)
axes[0].set_xlim(-lim, lim); axes[0].set_ylim(-lim, lim)
axes[0].set_xlabel('$x$'); axes[0].set_ylabel('$y$')
axes[0].set_title("Example 4.33: Stable Node ($\\lambda=-1,-6$)")
axes[0].legend(fontsize=8)
# det A = 0 case: Example 4.36
A436 = np.array([[1., 2.], [2., 4.]])
lim2 = 3.0
x_g2, y_g2 = np.meshgrid(np.linspace(-lim2, lim2, 22), np.linspace(-lim2, lim2, 22))
dx2 = A436[0,0]*x_g2 + A436[0,1]*y_g2
dy2 = A436[1,0]*x_g2 + A436[1,1]*y_g2
nrm2 = np.sqrt(dx2**2 + dy2**2 + 1e-10)
axes[1].quiver(x_g2, y_g2, dx2/nrm2, dy2/nrm2, alpha=0.3, color='gray', scale=28)
# Equilibrium line: x + 2y = 0 => y = -x/2
x_eq = np.linspace(-lim2, lim2, 200)
axes[1].plot(x_eq, -x_eq/2, 'k--', lw=2, label='Equil. line $x+2y=0$')
for x0_val in np.linspace(-lim2*0.9, lim2*0.9, 10):
for y0_val in [-lim2*0.6, lim2*0.6]:
sol = solve_ivp(lambda t, y: A436 @ y, (0, 0.4),
[x0_val, y0_val], dense_output=True, max_step=0.02)
xy = sol.y; mask = np.all(np.abs(xy) < lim2*1.4, axis=0)
axes[1].plot(xy[0, mask], xy[1, mask], 'steelblue', lw=1.2, alpha=0.7)
axes[1].axhline(0, color='k', lw=0.5); axes[1].axvline(0, color='k', lw=0.5)
axes[1].set_xlim(-lim2, lim2); axes[1].set_ylim(-lim2, lim2)
axes[1].set_xlabel('$x$'); axes[1].set_ylabel('$y$')
axes[1].set_title(r"Example 4.36: $\det A=0$, line of equilibria")
axes[1].legend(fontsize=9)
plt.suptitle("Real Unequal Eigenvalues — Nodes and Degenerate Cases", fontsize=12)
plt.tight_layout()
plt.show()