Linear ODE General Solution

lean4-proofdifferential-equationsvisualization
y(t)=eAty0 solves y=Ay,  y(0)=y0y(t) = e^{At}y_0 \text{ solves } y' = Ay,\; y(0)=y_0

Statement

Let AA be a real n×nn \times n matrix. The linear ODE system

y(t)=Ay(t),y(0)=y0Rny'(t) = A\, y(t), \qquad y(0) = y_0 \in \mathbb{R}^n

has a unique global solution given by the matrix exponential:

y(t)=eAty0,eAt:=k=0(At)kk!y(t) = e^{At} y_0, \qquad e^{At} := \sum_{k=0}^{\infty} \frac{(At)^k}{k!}

For a diagonal matrix A=diag(λ1,,λn)A = \operatorname{diag}(\lambda_1, \ldots, \lambda_n) the solution decouples:

yi(t)=eλit(y0)iy_i(t) = e^{\lambda_i t} (y_0)_i

Mathlib contains Matrix.exp and Matrix.exp_diagonal which state ediag(v)=diag(ev)e^{\operatorname{diag}(v)} = \operatorname{diag}(e^v), capturing exactly this decoupling.

Visualization

Scalar case y=2yy' = 2y, y(0)=3y(0) = 3: solution y(t)=3e2ty(t) = 3e^{2t}.

tte2te^{2t}y(t)=3e2ty(t) = 3e^{2t}
01.0003.000
0.52.7188.155
17.38922.167
254.598163.794

2-D diagonal example A=(1002)A = \begin{pmatrix}1 & 0 \\ 0 & -2\end{pmatrix}, y0=(1,1)y_0 = (1, 1):

eAt=(et00e2t),y(t)=(ete2t)e^{At} = \begin{pmatrix} e^{t} & 0 \\ 0 & e^{-2t} \end{pmatrix}, \qquad y(t) = \begin{pmatrix} e^{t} \\ e^{-2t} \end{pmatrix}
tty1(t)=ety_1(t) = e^ty2(t)=e2ty_2(t) = e^{-2t}
01.0001.000
12.7180.135
27.3890.018

The first component grows, the second decays — the eigenvalues control the long-term behavior.

Proof Sketch

  1. Existence. Define Φ(t)=eAt\Phi(t) = e^{At}. Then Φ(t)=AΦ(t)\Phi'(t) = A\Phi(t) because the power series can be differentiated term-by-term, giving ddt[(At)k/k!]=A(At)k1/(k1)!\frac{d}{dt}[(At)^k/k!] = A(At)^{k-1}/(k-1)!.
  2. Initial condition. Φ(0)=e0=I\Phi(0) = e^0 = I, so y(0)=Iy0=y0y(0) = I y_0 = y_0.
  3. Uniqueness. By the Picard–Lindelöf TheoremPicard–Lindelöf Theoremy=f(t,y),  y(t0)=y0    !solution on [t0ε,t0+ε]y' = f(t,y),\; y(t_0)=y_0 \implies \exists!\,\text{solution on }[t_0-\varepsilon, t_0+\varepsilon]A Lipschitz right-hand side guarantees a unique local solution to any ODE initial value problem.Read more →, the Lipschitz map f(t,y)=Ayf(t,y) = Ay (with constant A\|A\|) guarantees a unique solution.
  4. Diagonal decoupling. When A=diag(λ)A = \operatorname{diag}(\lambda), each power Ak=diag(λk)A^k = \operatorname{diag}(\lambda^k), so eAt=diag(eλt)e^{At} = \operatorname{diag}(e^{\lambda t}).

Connections

The matrix exponential is the bridge between the Cayley–Hamilton TheoremCayley–Hamilton TheorempA(A)=0  where  pA(λ)=det(λIA)p_A(A) = 0 \;\text{where}\; p_A(\lambda) = \det(\lambda I - A)Every square matrix satisfies its own characteristic polynomialRead more → (which constrains eAte^{At} to the characteristic polynomial) and the Spectral TheoremSpectral TheoremA=QΛQT  (real symmetric case)A = Q \Lambda Q^T \;\text{(real symmetric case)}Every real symmetric matrix is orthogonally diagonalizableRead more → (which diagonalizes symmetric AA, making eAte^{At} explicit). The scalar case relies on the Fundamental Theorem of CalculusFundamental Theorem of Calculusabf(x)dx=f(b)f(a)\int_a^b f'(x)\,dx = f(b) - f(a)Integration and differentiation are inverse operationsRead more → to differentiate power series term-by-term.

Lean4 Proof

import Mathlib.Analysis.Normed.Algebra.MatrixExponential

/-!
  Mathlib's `Matrix.exp_diagonal` states:
    exp (diagonal v) = diagonal (exp v)
  This is exactly the claim that for A = diag(λ), e^A = diag(e^λ).
  We instantiate it for a concrete 2×2 diagonal matrix.
-/

open Matrix in
/-- For a diagonal matrix, the matrix exponential diagonalises:
    exp(diag(λ)) = diag(exp(λ)).
    This is `Matrix.exp_diagonal` in Mathlib. -/
theorem matrix_exp_diagonal_two
    (λλ₂ : ) :
    NormedSpace.exp (diagonal (![λ₁, λ₂]))
      = diagonal (![NormedSpace.exp λ₁, NormedSpace.exp λ₂]) := by
  rw [exp_diagonal]
  congr 1
  funext i
  fin_cases i <;> simp

/-- Scalar ODE y' = c*y has solution y(t) = y₀ * exp(c*t).
    Verified by checking the derivative. -/
theorem scalar_linear_ode_solution (c y₀ : ) :
    let y :    := fun t => y₀ * Real.exp (c * t)
     t : , HasDerivAt y (c * y t) t := by
  intro y t
  have h := (Real.hasDerivAt_exp (c * t)).const_mul y₀
  have hc := hasDerivAt_id t |>.const_mul c
  convert h.comp t hc using 1
  simp [mul_comm]