Chaos, predictability, Koopman, DMD and SINDy
Before this lesson: linear algebra 05 (eigenvalues, complex pairs), linear algebra 08 (the SVD and the pseudoinverse) and linear algebra 12 (least squares); lesson 02 (RK4, stability) and lesson 03 (the tangent-linear model). Helpful: optimization 09 (sparse regression). Time: about 100 minutes, plus the notebook.
Why this matters #
Weather is chaotic. Lorenz found sensitive dependence on initial conditions in 1963 with the three-variable model of this lesson, a truncated model of convection. Today, skilful forecasts of day-to-day midlatitude weather reach about 10 days. Zhang et al. (2019) estimate that a 10 times smaller initial-condition error would add at most about 5 days. Lyapunov exponents explain why the gain is so small: they set how fast errors grow. They also explain three things you meet in this track:
- gradients through long rollouts explode (lesson 03);
- 4D-Var assimilation windows must be short (lesson 06);
- ML weather models are judged by ensembles and statistics at long lead times, not by one trajectory (lesson 16).
The second half is about learning dynamics from data. The Koopman operator turns nonlinear dynamics into linear dynamics on functions of the state. DMD is the best-fit linear model of snapshot data, and it approximates the Koopman operator. SINDy finds sparse, readable equations. These are standard tools in fluid dynamics and climate data analysis. They are also the ideas behind Koopman autoencoders and the linear latent dynamics of state-space models in ML.
1. Predict first #
2. The picture #
Errors that double: the simplest chaotic map #
Iterate a map from two nearby starting points. Their distance obeys (a first-order Taylor step). After steps,
The number is the Lyapunov exponent (per step): the average logarithmic stretching along the orbit. It is an average, not the local rate at one point.
Example. The doubling map has everywhere, so . Every step doubles the error. In binary, one step shifts all digits of one place to the left, so each step reveals one more binary digit of . In float64, the orbit of becomes exactly 0 after 55 steps: all the information in the starting value has been used up. The logistic map also has (the notebook checks it).
The predictability time. An error reaches a tolerance when , that is, after
The starting error enters only through a logarithm. A better initial condition helps, but only a little.
Fixed points and their type #
Now a flow , with (we use for the state, as in lessons 02 and 03). A fixed point has : a state that does not move. Near it, write . A Taylor step gives , with the Jacobian . This is a linear ODE, and its solutions are combinations of for the eigenpairs of (linear algebra 05). So:
- the real part of an eigenvalue decides growth () or decay () along its direction;
- the imaginary part decides rotation: a complex pair gives a spiral with angular frequency .
In the plane, the two eigenvalues are fixed by the trace and the determinant : . So one picture classifies every case.
Drag the orange point in the trace–determinant plane (left), or use the presets. The right side shows the phase portrait of a matrix with this trace and determinant: blue trajectories with arrows, and the eigenvector lines in yellow when the eigenvalues are real. Below the dashed parabola the eigenvalues are real; above it they are a complex pair. Notice that the sign of alone decides stability when .
| Eigenvalues of | Type | In the plane |
|---|---|---|
| real, both negative | stable node | , , below the parabola |
| real, opposite signs | saddle | |
| complex pair, negative real part | stable spiral | , , above the parabola |
| complex pair, positive real part | unstable spiral | , , above the parabola |
| purely imaginary pair | centre (for the linear system) | , |
In three dimensions there are three eigenvalues, and the same rules apply direction by direction. A real negative eigenvalue together with a complex pair of positive real part is a saddle-focus: trajectories come in along one direction and spiral out in a plane.
At a fixed point of a 3D system, the Jacobian has the eigenvalues and . What type of fixed point is it?
Stability needs every real part to be negative. The pair has a positive real part, so perturbations in its plane spiral outward with angular frequency , slowly. The size of does not help: it only acts along its own direction. A small real part is still not zero, so this is not a centre. These are the eigenvalues at the Lorenz-63 fixed points (section 3).
Two runs of a chaotic flow #
Lorenz-63 is the classic chaotic flow:
Every fixed point of it is unstable (section 3), yet trajectories stay bounded. They wander around two "wings", the Lorenz attractor, and never repeat. Start two trajectories very close together and watch.
Press Play, or move the time slider. Two Lorenz-63 trajectories start apart (blue and orange, shown in the plane). For a long time they look like one curve. The magenta curve below is their distance on a log axis. It wiggles, but on average it follows the dashed line of slope , until it saturates at the size of the attractor. Change by a factor 1000: the time to reach distance 1 moves by only about .
Chaos is stretching and folding at the same time. Stretching: some directions grow, so nearby states separate. Folding: the attractor is bounded, so the stretched set must fold back onto itself. Together they mix states: after a while, the state could be anywhere on the attractor.
For Lorenz-63, per time unit. About how long does it take for a small error to double?
The error grows like . It doubles when , so . The value is the Lyapunov time: the time for growth by the factor , not 2. The value is the time for growth by a factor 10. And itself is a rate, not a time.
Three ways to look at dynamics #
- States and nearby trajectories: fixed points, linearisation, Lyapunov exponents. This is the first half of the lesson.
- Observables: instead of moving the state, move functions of the state, for example the temperature at one place. The rule that moves them, the Koopman operator, is linear even when is not. The price: it acts on a space of functions, which is infinite-dimensional.
- Data: DMD fits the best linear map between snapshots of chosen observables. SINDy fits a sparse combination of candidate terms to the vector field .
The next figure shows the observable view on a nonlinear system with a known answer. In the state the trajectory bends, so no matrix can follow it. With one extra observable, , the same motion is exactly linear.
Drag the yellow start point, then switch the observables. The system is , . The blue curve is the true trajectory; it falls fast onto the grey parabola (the slow manifold) and then slides slowly along it. DMD uses the aqua snapshots () and its linear model is the orange dashed curve. With the state the model misses the bend and one rate is wrong. With the error drops to rounding level and the rates are exactly , and . The chart shows why: along the trajectory, the logarithms of the three Koopman eigenfunctions are straight lines.
3. Definitions and main results #
Fixed points and Lorenz-63 #
A fixed point is hyperbolic if no eigenvalue of has zero real part. Near a hyperbolic fixed point, the nonlinear flow looks like the linear flow (the Hartman–Grobman theorem): stable if all real parts are negative, a saddle if the signs are mixed, with spiralling where there are complex pairs. A centre is not hyperbolic, and there the linearisation can mislead: small nonlinear terms decide.
The Jacobian of Lorenz-63 is
Fixed points. gives . Then gives , and gives . So either (the origin), or and :
- At the origin, the eigenvalues are , and : a saddle.
- At , they are and : a saddle-focus (unstable spiral), because is above the Hopf value .
Every fixed point is unstable, yet trajectories stay bounded: they wander around and on the attractor. The trace of the Jacobian is at every point. So volumes in state space shrink by the factor per time unit (this follows from Liouville's formula, step 2 of the proof of Theorem 1 below).
Lyapunov exponents #
A small perturbation of a trajectory obeys the tangent-linear model (lesson 03). Collect all directions at once in the tangent propagator :
Definition. The Lyapunov exponents are
where are the singular values of (linear algebra 08). maps a small ball to an ellipsoid, and are its semi-axes, so is the average exponential growth rate of the -th axis.
Oseledets' theorem says that these limits exist and are the same for almost every starting point on the attractor (with respect to an ergodic invariant measure, here the natural measure of the attractor). For almost every , : a random perturbation turns towards the fastest-growing direction. A bounded system with is chaotic. For Lorenz-63 the exponents are (Sprott, 2003).
Theorem 1 (sum of the exponents). .
Why this is true, in one sentence: is the rate at which small volumes grow, and the volume of the ellipsoid is the product of its axes, , which grows at the rate .
Proof.
- Jacobi's formula: .
- has the same trace as (similar matrices). So , and (Liouville's formula).
- . Take the logarithm and divide by : .
- Let .
For Lorenz-63, is constant, so exactly. The strongly negative squeezes volumes, so the attractor has zero volume. Its Kaplan–Yorke dimension says that it is a thin set, a little more than two-dimensional.
Theorem 2 (a flow has a zero exponent). Let be a bounded trajectory of that does not converge to a fixed point, and assume that does not decay to zero exponentially fast. Then one Lyapunov exponent is . The reason: pushing the state along the trajectory only shifts it in time, and a time shift neither grows nor shrinks on average.
Proof of Theorem 2
The assumption means . It holds when the trajectory keeps coming back to a region where , away from the fixed points.
- Differentiate along the trajectory: .
- So solves the tangent-linear model, with . It is the perturbation that shifts the trajectory in time: .
- is bounded above (continuous on a bounded set), and by the assumption it does not go to zero exponentially. So : the growth rate in this direction is .
- By Oseledets' theorem, every direction grows at the rate of one of the exponents. So one equals .
Computing (Benettin's method). Integrate the state together with one tangent vector (the tangent-linear model, not a second trajectory). Every time units:
- add to a running sum;
- rescale to norm 1 (keep its direction).
After intervals, . The rescaling is needed: grows like and would overflow float64 near .
All exponents, and why two trajectories need care
To get all exponents, carry tangent vectors as the columns of . Every step, propagate them and re-orthonormalise with a QR factorisation (linear algebra 12). Then . Without QR, every vector would turn towards the fastest-growing direction and all estimates would approach .
The two-trajectory version (as in the figure) must also rescale the separation before it stops being small; otherwise the estimate saturates at the size of the attractor. A single pair also gives a noisy slope, because the local growth rate changes along the attractor.
Predictability. An error grows like . For Lorenz-63:
- the Lyapunov time is time units (growth by the factor );
- the doubling time is time units;
- the time to reach a tolerance is the predictability time .
Three consequences for this track:
- Training through rollouts. The gradient of a loss at time with respect to contains , so it grows like (lesson 03).
- Data assimilation. The 4D-Var cost function gets many local minima when the window is long, so windows are short (lesson 06).
- Forecasts depend on the day. The finite-time growth rate varies along the attractor, so predictability depends on the state of the flow. This is why ensemble forecasts show more spread on some days than on others.
The Koopman operator #
Take a discrete-time system . For a flow, is the flow map over a time step . An observable is a function of the state, for example the temperature at one point.
Definition. The Koopman operator acts on observables by composition with :
In words: is the observable ", one step later".
Proposition (linearity and eigenfunctions).
- is linear: for any , linear or not.
- If (a Koopman eigenfunction with eigenvalue ), then : along every trajectory, evolves exactly linearly.
- If are eigenfunctions with eigenvalues , then is an eigenfunction with eigenvalue .
Proof of the proposition
- . Nothing here uses linearity of : we only evaluate functions at the point .
- . Repeat times.
- .
The price: acts on a space of functions, which is infinite-dimensional. In continuous time, an eigenfunction with satisfies , and the flow map over has the eigenvalue .
Linear systems. For and a left eigenvector of (), the observable is an eigenfunction: .
A finite invariant subspace for a nonlinear system (Brunton and Kutz, §7.4). This is the system of the figure in section 2. With continuous-time rates and (here is a rate of the model, not a Lyapunov exponent):
Take the observables . Step by step:
- ;
- ;
- (chain rule).
So
a linear system, exactly, and . The nonlinear term is now a coordinate. The eigenvalues of are , and , with the eigenfunctions , with , and .
Check of the middle one: . This equals exactly when , that is, . The curve , where this eigenfunction is 0, is the slow manifold of the figure: the fast rate pulls every trajectory onto it.
For the logistic map , which statement about its Koopman operator is true?
for every , so is always linear. But is not a multiple of , so is not an eigenfunction. And has degree 4: the degree doubles at each application, so polynomials never close up into a finite subspace.
When no finite subspace exists. The quiz shows the first obstacle: for the logistic map the degree of the polynomials doubles at each step. For chaos the obstacle is deeper.
Mixing and the continuous Koopman spectrum
The Lorenz attractor is mixing (Luzzatto, Melbourne and Paccaut, 2005): any two regions of the attractor become, after a long time, statistically independent. On a mixing attractor the only eigenfunctions of in of the invariant measure are the constants, and the rest of the spectrum is continuous. A finite linear model of chaos can therefore only be approximate, and only over short horizons. Practical methods (extended DMD with many observables, delay coordinates, Koopman autoencoders) give good short-term predictions and useful coherent patterns, not an exact finite linear system.
Koopman modes. Suppose each state component is a combination of eigenfunctions, . Then : the state is a sum of fixed spatial patterns (the Koopman modes), each with one growth rate and one frequency. DMD estimates the pairs from data, with the state coordinates as observables.
Dynamic mode decomposition (DMD) #
Data. Snapshot pairs with , usually at spacing . (From here on we write for a data vector, as in the DMD literature.) Arrange them as columns:
with the number of measured values per snapshot (for example grid points) and the number of snapshots.
The best-fit linear map. , with the pseudoinverse (linear algebra 08). Each row of is a least-squares problem, and gives the minimum-norm solution. For a field with grid points, has entries. Exact DMD never forms it.
Exact DMD (Tu et al., 2014, Algorithm 2):
- Reduced SVD , truncated to rank : (), , ().
- Projected operator (). It equals for : the map seen in the coordinates of the top singular vectors.
- Eigendecomposition . The diagonal of holds the DMD eigenvalues .
- Exact DMD modes (). A mode is defined only up to a scale factor (Tu et al. divide column by ; Brunton and Kutz do not).
- Continuous-time rates : growth rate and angular frequency . Amplitudes , and the model , where is column of .
The cost is one thin SVD, , plus small problems.
Reading a DMD eigenvalue. Write . Then :
- : the mode decays; : it neither grows nor decays; : it grows;
- the angle is the rotation per step, so the angular frequency is .
Move the rank , then add noise. The data (left map) are two travelling waves, one neutral and one decaying, plus sensor noise; violet is negative, yellow positive. The right map is the rank- DMD model, rolled out from the first snapshot. In the complex plane, the orange dots are the DMD eigenvalues and the blue rings the true ones. With they match: two on the unit circle, two just inside. With a wave is missing. With noise and , extra eigenvalues appear deep inside the circle: they fit noise. The singular values (top right) show the gap after 4.
Theorem 3 (exact DMD modes are eigenvectors of ; Tu et al., Theorem 1). Let . If with , then is nonzero and . Conversely, every nonzero eigenvalue of is an eigenvalue of .
Proof of Theorem 3
Write , so that and . (The two products of the same two matrices in the two orders: this is the whole trick.)
- .
- If , then , so , a contradiction. So .
- Conversely, let with , and . Then .
- : if , then , so .
The older projected modes are the projections of the exact modes onto the column space of . They are not eigenvectors of in general.
Theorem 4 (DMD recovers a linear system). If for all and has rank , then , and exact DMD with returns the eigenvalues of .
Proof.
- , so .
- is the orthogonal projector onto the column space of , which is all of when . So and .
- With , Theorem 3 gives all nonzero eigenvalues of . ( is invertible when it comes from a flow map, so no eigenvalue is 0.)
If the data span only a subspace (for example one trajectory inside an invariant subspace), then , with the projector onto : DMD sees only the modes that the data excite.
DMD with returns the eigenvalue . What does this mode do?
. The size means decay by 10% per step, which is per time unit. The angle is per step too, so the angular frequency is per time unit. The sign of only says where the point is in the plane, not growth.
DMD in practice.
- Rank . Too large with noisy data gives spurious eigenvalues; too small misses dynamics. Look for a gap in the singular values. Gavish–Donoho hard thresholding is a principled choice.
- Noise. Least squares treats as exact, so sensor noise biases the eigenvalues towards the origin (too much damping; in the figure, try ). Forward–backward and total-least-squares DMD reduce this bias (Dawson et al., 2016).
- Few observables. A scalar signal needs the two eigenvalues , but a matrix has one. Stack time-delayed copies (a Hankel matrix) to get enough rows: this is time-delay embedding.
- Sampling. is unique only for ; faster oscillations alias (they look like slower ones).
- DMD or POD (PCA)? Proper orthogonal decomposition (POD), also called PCA or EOF analysis, ranks spatial patterns by variance and ignores the time order of the snapshots (linear algebra 09). A DMD mode is a pattern with one frequency and one growth rate. So DMD can separate, for example, an annual cycle from a slower oscillation that has a similar variance, where POD would mix them.
SINDy: sparse identification of nonlinear dynamics #
Model. Assume that each component of is a sparse combination of known candidate functions: . Here is a row of library functions of the state (for the Lorenz state : ), and is sparse: most entries are 0. With samples, stack the states as rows of (), the time derivatives as rows of , and the library as ():
Column of is a regression problem for . We want few nonzero coefficients, so that the result is a short equation. This is like the lasso, (optimization 09), but SINDy usually uses a simpler method.
Sequentially thresholded least squares (STLSQ) (Brunton, Proctor and Kutz, 2016):
- the least-squares solution of (dense: every term is used).
- Set every entry with to zero. The threshold is called in the book.
- For each column , refit by least squares using only the library terms that are still active.
- Repeat steps 2–3 until the set of active terms no longer changes.
Proposition (STLSQ stops). The active set of each column never grows, so STLSQ reaches a fixed point after at most changes per column.
Proof. An entry set to zero in step 2 is excluded from the refit in step 3, so it stays zero: entries can leave the active set but never return. Each change removes at least one of the terms. When no entry falls below , steps 2–3 change nothing.
For Lorenz-63 with all monomials up to degree 2 (), has 30 entries and 7 of them are nonzero: (for : , ); (for : , , ); (for : , ).
Move the threshold, then add noise. The bars are the 30 coefficients of the first, dense least-squares fit, on a log axis: blue for the 7 true terms, magenta for the 23 terms that should be 0. The yellow line is the threshold . Below it, the equations that STLSQ returns; wrong extra terms appear in magenta. STLSQ succeeds when the line separates the blue bars from the magenta bars. Notice that the smallest true coefficient is 1, so no threshold above 1 can work.
Choices that decide success:
- The library must contain the true terms, in good coordinates. SINDy cannot invent a term that is not in the list.
- The threshold must lie between the largest spurious coefficient and the smallest true one (here ). Normalise the library columns, or the threshold means different things for and .
- Derivatives. Finite differences amplify noise by about . Use smoothed or total-variation-regularised derivatives, or the weak (integral) form of SINDy.
- Relation to DMD: with a linear library, a discrete-time target and no threshold, SINDy is DMD.
You run STLSQ on clean Lorenz-63 data with the threshold . What happens?
Step 2 deletes every coefficient below in absolute value, true or not. The smallest true coefficients have size 1 < 2, so they are removed and never come back (the active set only shrinks). The refit then forces the remaining terms to explain the missing ones. The threshold must sit between the largest spurious coefficient (about 0.004 here) and the smallest true one (1).
Answers to section 1. (1) The separation grows like . It reaches order 1 after time units, and the size of the attractor (about 20) about 3 time units later. A 1000 times smaller error gains only time units. (2) Not in the state coordinates: the fixed points of form a linear subspace (the null space of ), so a linear model cannot have the three isolated fixed points of Lorenz-63. With observables it can work exactly for some systems (the slow-manifold example), but never for a chaotic one, whose Koopman spectrum is continuous.
4. Worked example #
(a) DMD by hand. Data from with and .
Step 1, the snapshots: and .
Step 2, the data matrices (the snapshots and their successors ):
Step 3, the pseudoinverse. is square with , so :
Step 4, the product , row by row:
This is (Theorem 4). Step 5, the eigenvalues: the matrix is triangular, so and , with the eigenvectors (modes) and . The continuous-time rates are and . Both modes decay; the second one more slowly.
(b) Lifting makes DMD exact. In the slow-manifold system take , and .
- The Koopman eigenvalues of the flow map are , and .
- .
- On a trajectory from over , DMD on the state returns the rates and . The rate is right, because the equation is linear. The rate is wrong: it is neither nor . A matrix has room for only two rates, so the least-squares fit mixes the effects of and .
- DMD on returns , and , and the fitted matrix equals to about (section 5).
(c) Lorenz numbers without simulation.
- Sum of the exponents: .
- With and : (Sprott: ).
- Kaplan–Yorke dimension: .
- Doubling time: time units.
(d) One STLSQ step by hand. The first, dense least-squares fit in section 5 (the array dense) gives, for , the
coefficients (), (), (), and every other coefficient below
in absolute value.
- With , step 2 keeps and deletes the other 7 terms.
- Step 3 refits on these three columns only.
- The next step 2 deletes nothing, so STLSQ stops.
Any between about and gives the right active set here; deletes the true terms and (and in ).
5. In code #
The first block finds the Lorenz fixed points and estimates with Benettin's method:
import numpy as np
sigma, rho, beta = 10.0, 28.0, 8 / 3
def f(u): # Lorenz-63
x, y, z = u
return np.array([sigma * (y - x), x * (rho - z) - y, x * y - beta * z])
def jac(u): # its Jacobian J = df/du
x, y, z = u
return np.array([[-sigma, sigma, 0.0], [rho - z, -1.0, -x], [y, x, -beta]])
c = np.sqrt(beta * (rho - 1)) # C± = (±c, ±c, ρ - 1)
for p in [(0, 0, 0), (c, c, rho - 1)]:
print(np.round(np.sort_complex(np.linalg.eigvals(jac(np.array(p)))), 3))
# [-22.828+0.j -2.667+0.j 11.828+0.j] saddle at the origin
# [-13.855 +0.j 0.094-10.195j 0.094+10.195j] saddle-focus at C+
print(np.trace(jac(np.zeros(3)))) # -13.666666666666666 = -(σ + 1 + β)
def rk4(F, u, h):
k1 = F(u); k2 = F(u + h / 2 * k1); k3 = F(u + h / 2 * k2); k4 = F(u + h * k3)
return u + h / 6 * (k1 + 2 * k2 + 2 * k3 + k4)
# Benettin: state + one tangent vector d (d' = J(u) d), renormalised every step
G = lambda w: np.concatenate([f(w[:3]), jac(w[:3]) @ w[3:]])
h, u = 0.01, np.array([1.0, 1.0, 1.0])
for _ in range(2000): # 20 time units of transient
u = rk4(f, u, h)
w, total, n = np.concatenate([u, [1.0, 0.0, 0.0]]), 0.0, 50_000
for _ in range(n):
w = rk4(G, w, h)
g = np.linalg.norm(w[3:]); total += np.log(g); w[3:] /= g
lam1 = total / (n * h)
print(f"{lam1:.3f} doubling time {np.log(2) / lam1:.2f}") # 0.908 doubling time 0.76
Over 500 time units the estimate is ; longer runs converge to . The second block is exact DMD from the SVD, on the worked examples (a) and (b):
import numpy as np
from scipy.linalg import expm
def exact_dmd(X, Xp, r):
"""Exact DMD (Tu et al. 2014): eigenvalues mu and modes Phi of A = X' X^+, rank r."""
U, s, Vh = np.linalg.svd(X, full_matrices=False)
U, s, V = U[:, :r], s[:r], Vh[:r].conj().T
At = U.conj().T @ Xp @ V / s # r x r projected operator
mu, W = np.linalg.eig(At)
Phi = Xp @ V / s @ W # exact DMD modes
return mu, Phi
# (a) the 2x2 worked example: DMD returns the matrix that made the data
A_true = np.array([[0.5, 0.2], [0.0, 0.8]])
snaps = [np.array([1.0, 1.0])]
for _ in range(2):
snaps.append(A_true @ snaps[-1])
S = np.column_stack(snaps)
mu, Phi = exact_dmd(S[:, :-1], S[:, 1:], r=2)
print(np.sort(mu.real), np.sort(np.log(mu.real) / 0.1).round(3)) # [0.5 0.8] [-6.931 -2.231]
print(np.abs(A_true @ Phi - Phi * mu).max() < 1e-12) # True: A φ = μ φ
# (b) the slow-manifold system, sampled exactly: state vs lifted observables
mu_, lam, dt = -0.05, -1.0, 0.1
t = np.arange(0, 10 + 1e-9, dt)
x1 = 1.5 * np.exp(mu_ * t)
b = lam / (lam - 2 * mu_)
x2 = (-1.0 - b * 1.5**2) * np.exp(lam * t) + b * x1**2 # exact solution from (1.5, -1)
rates = lambda Z, r: np.sort(np.log(exact_dmd(Z[:, :-1], Z[:, 1:], r)[0]).real / dt)
print(rates(np.vstack([x1, x2]), 2).round(3)) # [-1.222 -0.05 ]: one rate is wrong
lifted = np.vstack([x1, x2, x1**2])
print(rates(lifted, 3).round(3)) # [-1. -0.1 -0.05]: λ, 2μ, μ
K = np.array([[mu_, 0, 0], [0, lam, -lam], [0, 0, 2 * mu_]])
A_fit = lifted[:, 1:] @ np.linalg.pinv(lifted[:, :-1])
print(f"{np.abs(A_fit - expm(K * dt)).max():.0e}") # 3e-15
The third block is SINDy on Lorenz-63, with derivatives estimated from the data:
import numpy as np
from scipy.integrate import solve_ivp
rhs = lambda t, u: [10 * (u[1] - u[0]), u[0] * (28 - u[2]) - u[1], u[0] * u[1] - 8 / 3 * u[2]]
dt = 0.002
t = np.arange(0, 20, dt)
X = solve_ivp(rhs, (0, t[-1]), [-8.0, 8.0, 27.0], t_eval=t, method="DOP853",
rtol=1e-12, atol=1e-12).y.T # 10,000 states, shape (10000, 3)
dX = np.gradient(X, dt, axis=0, edge_order=2) # derivatives from the data
x, y, z = X.T
names = ["1", "x", "y", "z", "x^2", "xy", "xz", "y^2", "yz", "z^2"]
Theta = np.column_stack([np.ones_like(x), x, y, z, x*x, x*y, x*z, y*y, y*z, z*z])
def stlsq(Theta, dX, eta, iters=10):
Xi = np.linalg.lstsq(Theta, dX, rcond=None)[0] # step 1: dense least squares
for _ in range(iters):
small = np.abs(Xi) < eta # step 2: threshold
Xi[small] = 0
for k in range(dX.shape[1]): # step 3: refit the active terms
big = ~small[:, k]
Xi[big, k] = np.linalg.lstsq(Theta[:, big], dX[:, k], rcond=None)[0]
return Xi
dense = np.linalg.lstsq(Theta, dX, rcond=None)[0]
true = np.zeros((10, 3))
true[[1, 2], 0] = [-10, 10]; true[[1, 2, 6], 1] = [28, -1, -1]; true[[3, 5], 2] = [-8 / 3, 1]
print(f"largest spurious |xi| in the dense fit: {np.abs(dense[true == 0]).max():.4f}") # 0.0040
Xi = stlsq(Theta, dX, eta=0.1)
for name, row in zip(names, Xi):
if np.any(row):
print(f"{name:>4}", " ".join(f"{v:9.4f}" for v in row))
# x -9.9992 27.9924 0.0000
# y 9.9992 -0.9986 0.0000
# z 0.0000 0.0000 -2.6664
# xy 0.0000 0.0000 0.9999
# xz 0.0000 -0.9998 0.0000
rel = np.abs(Xi[true != 0] - true[true != 0]) / np.abs(true[true != 0])
print(f"same terms: {np.array_equal(Xi != 0, true != 0)}, largest relative error {rel.max():.2%}")
# same terms: True, largest relative error 0.14%
The dense fit already has the seven true coefficients within 0.25% (the error comes from the second-order differences), and every spurious one is below 0.005. STLSQ removes the spurious terms, and the refit brings the largest relative error to 0.14%. PyDMD and PySINDy are the standard libraries for these methods; the notebook builds them from scratch.
6. Where it shows up #
- Weather and climate. Lorenz-63 and Lorenz-96 are the test beds of data assimilation (lesson 06). Lyapunov exponents explain the predictability limit, the need for ensembles, and why a perfect emulator still diverges from the truth. So long rollouts are evaluated by statistics, spectra and probabilistic scores (CRPS, lesson 07), not by pointwise error at long lead times.
- Climate patterns. DMD-type methods extract oscillating modes from geophysical fields: multi-resolution DMD on sea-surface temperature data from 1990–2010 isolates the 1997 El Niño as its own mode (Kutz, Fu and Brunton, 2016).
- Seismology. Simple spring–slider models of a fault with friction are chaotic (Huang and Turcotte, 1990). This is one argument for why the exact timing of earthquakes is hard to predict, and why seismic hazard is stated as a probability.
- Training through dynamics. Backpropagation through a rollout of length of a chaotic model multiplies gradients by about (lesson 03). Short rollouts keep these gradients and the memory cost under control: GraphCast trains with rollouts of at most 12 six-hour steps (Lam et al., 2023).
- Machine learning. Koopman autoencoders learn coordinates in which the dynamics are linear (Lusch, Kutz and Brunton, 2018); SINDy autoencoders learn coordinates in which the dynamics are sparse (Champion et al., 2019). State-space layers (S4, Mamba) also evolve a latent state by a linear recurrence and read it out nonlinearly (deep learning 16).
- Equation discovery and closures. SINDy and its PDE version identify reduced models of fluid and plasma flows and subgrid closure terms.
7. Common mistakes #
- Estimating from two trajectories without rescaling, or over a too short time. The separation saturates at the attractor size, and finite-time rates fluctuate along the attractor.
- Mixing units. An exponent per sampling step equals , where is the exponent per unit time. In the same way, a DMD eigenvalue is per step and is per unit time.
- Reading as growth. Growth or decay is decided by compared with 1 (or by ), not by the sign of .
- Too coarse sampling for DMD. Frequencies above alias.
- Calling the projected modes exact DMD modes, or choosing the rank by eye on noisy data.
- Believing that a finite linear model can be exact for chaos. Truncated Koopman models of chaotic systems are short-horizon approximations.
- SINDy: a library without the true terms; a threshold above the smallest true coefficient; unnormalised columns; raw finite differences of noisy data.
- Reading a DMD eigenvalue near 1 as dynamics when it is just the mean of the data (a constant observable has ). Subtract the mean first, or keep this in mind.
8. Check yourself #
- For Lorenz-63, and . Find without any simulation.
Answer
Theorem 1 with the constant trace: , so . - Suppose a single exponent described weather error growth. What makes a 10 times
smaller initial error add 5 days of skill (the estimate of Zhang et al.)? What is the doubling time?
Answer
, so dividing by 10 adds days: per day, and the doubling time is days. (Real error growth is faster at small scales and saturates there, so one exponent is a simplification.) - Data come from with and . What does DMD
return, and why?
Answer
Every snapshot is a multiple of , so and . DMD finds only . The mode with is never excited, so the data cannot reveal it (Theorem 4 needs ). - Show that is a Koopman eigenfunction of the slow-manifold system, and give its eigenvalue
in continuous time and for the flow map over .
Answer
, so : the continuous-time eigenvalue is , and the flow-map eigenvalue is . It is the product of the eigenfunction with itself, so its eigenvalue is the square of . - Why does DMD on the scalar signal fail, and how do time delays fix it?
Answer
A fit has one real eigenvalue, but needs the pair . The signal satisfies , so the delay vector evolves by an exact linear map with eigenvalues . DMD on the Hankel matrix recovers them. - You run STLSQ on noisy Lorenz data and get extra terms such as in . Name two
fixes.
Answer
Better derivatives (smoothing, total-variation regularisation, or the weak/integral form); a larger threshold (still below the smallest true coefficient, 1) after normalising the library columns; more data; or a shorter library. Then check the fitted model by simulating it and comparing statistics with the data.
Define the largest Lyapunov exponent of a trajectory.
The long-time average exponential growth rate of a small perturbation: for almost every , with from the tangent-linear model.
What is for Lorenz-63 (, , ), and what is the doubling time of an error?
per time unit; doubling time time units.
What is the sum of all Lyapunov exponents, and why?
The time average of . By Liouville's formula , and .
Give the predictability time for an error and a tolerance .
. The starting error enters only through a logarithm.
Why must Benettin's method renormalise the tangent vector?
It grows like and would overflow (near for Lorenz-63). Renormalising and summing keeps the same information.
Define the Koopman operator, and say why it is linear.
: composition with the dynamics. , for any .
Give the exact DMD formula for the projected operator and the modes.
With : , , modes .
A DMD eigenvalue is with time step . What are its growth rate and angular frequency?
: growth rate , angular frequency .
What problem does SINDy solve?
Find a sparse with , where is a library of candidate functions; STLSQ alternates least squares with setting to zero.
DMD or POD: what is the difference in what a mode means?
A POD (PCA) mode is a pattern ranked by variance, with no time information. A DMD mode is a pattern with one growth rate and one frequency, from the best-fit linear map.
9. Interview angle #
Typical questions and short model answers:
- "What is a Lyapunov exponent, and what does it mean for forecasting?" — The average exponential rate at which nearby trajectories separate. The predictability time grows only like , so better observations help little; hence ensembles and probabilistic scores.
- "What is the Koopman operator? What is the catch?" — Composition with the dynamics; it is linear on observables. It is infinite-dimensional, and for chaos its spectrum is continuous, so finite models are approximate.
- "DMD or PCA/POD?" — POD ranks patterns by variance; DMD gives patterns with one frequency and one growth rate each, from the best-fit linear map. Exact DMD never forms .
- "How would you discover equations from data, and what breaks it?" — SINDy: a library plus sparse regression. It breaks with noisy derivatives, a library without the right terms, or bad coordinates.
- "Your emulator matches the truth for 5 days and then drifts, although its one-step error is tiny. Is it broken?" — Not necessarily. With any small error grows. Evaluate statistics, spectra and ensemble scores instead of pointwise error at long lead times.
10. Practice #
The notebook for this lesson runs in Colab or in the browser. It has five exercises, each with a check cell and a folded solution:
- Find the fixed points of Lorenz-63 and classify them with the eigenvalues of the Jacobian.
- Estimate the largest Lyapunov exponent with the tangent-linear model and renormalisation (≈ 0.906).
- Write exact DMD from the SVD and check that it recovers the eigenvalues of a known linear system.
- Compare DMD on the state and on the lifted observables of the slow-manifold system.
- Write STLSQ and recover the Lorenz-63 coefficients from data within 1%.
11. Watch and read #
- Brunton and Kutz, Data-Driven Science and Engineering, 2nd edition, free draft from the authors, chapter 7: §7.1 (Lorenz and the challenges), §7.2 (DMD: the exact DMD algorithm and the spectral expansion), §7.3 (SINDy, with code for STLSQ and the Lorenz example), §7.4 (Koopman operator theory, the slow-manifold example and the logistic map), §7.5 (data-driven Koopman analysis: EDMD and delay coordinates).
- Tu, Rowley, Luchtenburg, Brunton and Kutz, On dynamic mode decomposition: theory and applications (2014): §2.2 (exact DMD, Algorithm 2, Theorems 1–2), §2.3 (projected versus exact modes), §4.1 (Koopman spectral analysis).
- Brunton, Proctor and Kutz, Discovering governing equations from data by sparse identification of nonlinear dynamical systems, PNAS (2016): the original SINDy paper (free arXiv version).
- Strogatz, Nonlinear Dynamics and Chaos (book): chapters 5–6 (linear systems and phase plane, classification of fixed points) and chapter 9 (the Lorenz equations).
- Sprott, Chaos and Time-Series Analysis (Oxford, 2003): the Lyapunov exponents of Lorenz-63 used here.
- Zhang, Sun, Magnusson, Buizza, Lin, Chen and Emanuel, What is the predictability limit of midlatitude weather?, Journal of the Atmospheric Sciences (2019).
- Papers cited in the lesson: Luzzatto, Melbourne and Paccaut, The Lorenz attractor is mixing (2005); Kutz, Fu and Brunton, Multi-resolution dynamic mode decomposition (2016); Lusch, Kutz and Brunton, Deep learning for universal linear embeddings of nonlinear dynamics (2018); Champion, Lusch, Kutz and Brunton, Data-driven discovery of coordinates and governing equations (2019); Lam et al., GraphCast: Learning skillful medium-range global weather forecasting (2023); Huang and Turcotte, Are earthquakes an example of deterministic chaos?, Geophysical Research Letters 17 (1990).
- Libraries: PyDMD and PySINDy.
Runs in your browser with nothing to install. The notebook repeats the key demos and has exercises with checks; solutions are inside, folded.
No Google account needed: Python runs inside your browser. The first start downloads about 40 MB; your changes are saved in this browser only.