Phase Portraits and Fixed Point ClassificationΒΆ
This notebook explores the relationship between eigenvalues of a linear system's matrix and the qualitative behaviour of its phase portrait. We classify fixed points as stable nodes, saddle points, spirals, and centres, then apply the same tools to a nonlinear Lotka-Volterra system via linearization.
load("numerics")$
load("ax-plots")$
Linear SystemsΒΆ
For a linear system $\dot{\mathbf{x}} = A\mathbf{x}$, the eigenvalues of $A$ completely determine the phase portrait near the origin. We work through each case.
Stable Node [S+N]ΒΆ
When both eigenvalues are real and negative, all trajectories converge to the origin along the eigenvector directions. The system is asymptotically stable.
/* Stable node: both eigenvalues negative */
A_node : matrix([-2, 0], [0, -1])$
evals_node : eigenvalues(A_node);
print("Eigenvalues:", evals_node[1])$
print("Both negative real => stable node")$
[[-2,-1],[1,1]] Eigenvalues: [-2,-1] Both negative real => stable node
/* Phase portrait: trajectories converge to origin */
ax_draw2d(
ax_vector_field(-2*x, -y, x, -3, 3, y, -3, 3),
ax_streamline(-2*x, -y, x, -3, 3, y, -3, 3),
title="Stable Node",
xlabel="x", ylabel="y",
aspect_ratio=true
)$
Saddle Point [S+N]ΒΆ
When eigenvalues are real with opposite signs, trajectories approach the origin along the stable eigenvector and diverge along the unstable eigenvector. The fixed point is unstable.
/* Saddle point: eigenvalues of opposite sign */
A_saddle : matrix([1, 0], [0, -2])$
evals_saddle : eigenvalues(A_saddle);
print("Eigenvalues:", evals_saddle[1])$
print("One positive, one negative => saddle point")$
[[-2,1],[1,1]] Eigenvalues: [-2,1] One positive, one negative => saddle point
/* Saddle point phase portrait: hyperbolic trajectories */
ax_draw2d(
ax_vector_field(x, -2*y, x, -3, 3, y, -3, 3),
ax_streamline(x, -2*y, x, -3, 3, y, -3, 3),
title="Saddle Point",
xlabel="x", ylabel="y",
aspect_ratio=true
)$
Stable Spiral [S+N]ΒΆ
When eigenvalues are complex conjugates with negative real part, trajectories spiral inward toward the origin. The imaginary part determines the rotation frequency.
/* Stable spiral: complex eigenvalues with negative real part */
A_spiral : matrix([-1, 2], [-2, -1])$
evals_spiral : eigenvalues(A_spiral);
print("Eigenvalues:", evals_spiral[1])$
print("Complex with Re < 0 => stable spiral")$
[[-(2*%i)-1,2*%i-1],[1,1]] Eigenvalues: [-(2*%i)-1,2*%i-1] Complex with Re < 0 => stable spiral
/* Stable spiral: trajectories wind inward */
ax_draw2d(
ax_vector_field(-x + 2*y, -2*x - y, x, -3, 3, y, -3, 3),
ax_streamline(-x + 2*y, -2*x - y, x, -3, 3, y, -3, 3),
title="Stable Spiral",
xlabel="x", ylabel="y",
aspect_ratio=true
)$
Unstable SpiralΒΆ
When the real part of complex eigenvalues is positive, trajectories spiral outward from the origin.
/* Unstable spiral: complex eigenvalues with positive real part */
A_uspiral : matrix([1, 2], [-2, 1])$
evals_uspiral : eigenvalues(A_uspiral);
print("Eigenvalues:", evals_uspiral[1])$
print("Complex with Re > 0 => unstable spiral")$
[[1-2*%i,2*%i+1],[1,1]] Eigenvalues: [1-2*%i,2*%i+1] Complex with Re > 0 => unstable spiral
/* Unstable spiral: trajectories wind outward */
ax_draw2d(
ax_vector_field(x + 2*y, -2*x + y, x, -3, 3, y, -3, 3),
ax_streamline(x + 2*y, -2*x + y, x, -3, 3, y, -3, 3),
title="Unstable Spiral",
xlabel="x", ylabel="y",
aspect_ratio=true
)$
CentreΒΆ
The simple harmonic oscillator $\dot{x} = y$, $\dot{y} = -x$ has pure imaginary eigenvalues. Trajectories form closed orbits -- neither converging nor diverging.
/* Centre: pure imaginary eigenvalues */
A_centre : matrix([0, 1], [-1, 0])$
evals_centre : eigenvalues(A_centre);
print("Eigenvalues:", evals_centre[1])$
print("Pure imaginary => centre (closed orbits)")$
[[-%i,%i],[1,1]] Eigenvalues: [-%i,%i] Pure imaginary => centre (closed orbits)
/* Centre: closed circular orbits */
ax_draw2d(
ax_vector_field(y, -x, x, -3, 3, y, -3, 3),
ax_streamline(y, -x, x, -3, 3, y, -3, 3),
title="Centre (Simple Harmonic Oscillator)",
xlabel="x", ylabel="y",
aspect_ratio=true
)$
Nonlinear Example: Lotka-Volterra [S+N]ΒΆ
The classical predator-prey model:
$$\dot{x} = x(1-y) \qquad \dot{y} = y(x-1)$$
where $x$ is the prey population and $y$ is the predator population. We use Maxima's symbolic tools to compute the Jacobian, find fixed points, and classify their stability.
/* Lotka-Volterra system */
f1 : x*(1 - y)$
f2 : y*(x - 1)$
/* Compute the Jacobian symbolically */
J_lv : matrix(
[diff(f1, x), diff(f1, y)],
[diff(f2, x), diff(f2, y)]
);
print("Jacobian:")$
J_lv;
matrix([1-y,-x],[y,x-1]) Jacobian:
/* Find fixed points */
fps_lv : solve([f1 = 0, f2 = 0], [x, y]);
print("Fixed points:")$
for fp in fps_lv do print(fp)$
[[x = 0,y = 0],[x = 1,y = 1]] Fixed points: [x = 0,y = 0] [x = 1,y = 1]
/* Classify each fixed point via eigenvalues of the Jacobian */
for fp in fps_lv do block(
[J_fp, evals],
J_fp : subst(fp, J_lv),
evals : eigenvalues(J_fp),
print("--- Fixed point:", fp, "---"),
print(" J =", J_fp),
print(" Eigenvalues =", evals[1]),
if every(lambda([e], is(float(realpart(e)) < 0)), evals[1]) then
print(" Classification: STABLE")
elseif every(lambda([e], is(float(realpart(e)) > 0)), evals[1]) then
print(" Classification: UNSTABLE")
elseif every(lambda([e], is(float(realpart(e)) = 0)), evals[1]) then
print(" Classification: CENTRE")
else
print(" Classification: SADDLE")
)$
--- Fixed point: [x = 0,y = 0] --- J = matrix([1,0],[0,-1]) Eigenvalues = [-1,1] Classification: SADDLE --- Fixed point: [x = 1,y = 1] --- J = matrix([0,-1],[1,0]) Eigenvalues = [-%i,%i] Classification: SADDLE
/* Phase portrait of the Lotka-Volterra system */
ax_draw2d(
color="#cccccc",
ax_vector_field(f1, f2, x, 0, 4, y, 0, 4),
color="#e41a1c",
initial_points=[[0.5, 0.5], [1.0, 2.0], [2.0, 0.5],
[0.5, 1.5], [3.0, 1.0], [1.5, 3.0]],
ax_streamline(f1, f2, x, 0, 4, y, 0, 4),
title="Lotka-Volterra Phase Portrait",
xlabel="x (prey)", ylabel="y (predator)",
aspect_ratio=true
)$
Summary: Eigenvalue ClassificationΒΆ
| Eigenvalues | Portrait Type | Stability |
|---|---|---|
| Both real, both negative | Stable node | Asymptotically stable |
| Both real, both positive | Unstable node | Unstable |
| Both real, opposite signs | Saddle point | Unstable |
| Complex, Re < 0 | Stable spiral | Asymptotically stable |
| Complex, Re > 0 | Unstable spiral | Unstable |
| Pure imaginary | Centre | Marginally stable (Lyapunov) |
For nonlinear systems, the same classification applies locally at each fixed point via the Jacobian. The Lotka-Volterra system demonstrates this: a saddle at the origin and a centre at the coexistence equilibrium, producing the characteristic closed predator-prey cycles.