Learning Objectives
By the end of this section you will be able to:
- Recognise a system of first-order ODEs and write it in vector form .
- Identify the coupling between equations — the off-diagonal terms that prevent you from solving one variable at a time.
- Reduce any single n-th order ODE to an equivalent first-order system of size n.
- Interpret a solution as a curve in the phase plane and as two time-series stacked together.
- State the existence-and-uniqueness theorem for systems and explain why a system of size n needs exactly n initial conditions.
- Implement a forward-Euler and an RK4 integrator for a 2-D linear system in Python, and reproduce the same trajectory in PyTorch using the matrix exponential.
Why Systems? Two Quantities That Talk to Each Other
Almost nothing in the real world evolves alone.
Up to now every ODE has had one unknown function: — the temperature of a cooling cup, the charge on a single capacitor, the position of one bouncing mass. That picture works only when the quantity in question does not depend on anything else changing in time. The moment two quantities influence each other's rate of change, a single ODE is no longer enough.
Look around. Predators eat prey, so the rabbit population determines how fast the fox population grows — but the fox population in turn determines how fast rabbits disappear. In an RLC circuit, the rate of change of current depends on the voltage across the capacitor; the rate of change of that voltage depends on the current. In a chemical reactor, the production rate of compound A depends on how much B is present, and the consumption rate of B depends on A. In every one of these examples a single equation can not describe the dynamics — you need at least two, and they have to be solved simultaneously.
The big idea
A system of ODEs describes the joint evolution of several quantities whose rates of change all depend on the same state. The mathematics generalises gracefully: every tool you have for one ODE has an analogue for systems, only now the unknown is a vector and the right-hand side is a vector field .
A Concrete Picture: Two Coupled Tanks
Picture two tanks of brine, side by side, connected by a pipe. Pure water flows in from above at a constant rate; salty water flows out the bottom; and brine sloshes back and forth through the connecting pipe at a rate proportional to the difference in salt concentrations. Let be the mass of salt in tank 1 and the mass of salt in tank 2.
Track only tank 1 for a moment. Salt enters from tank 2 at rate (more salt next door → more salt coming in). Salt leaves through the outlet AND through the connecting pipe at rate . So
Now do the same accounting for tank 2 — by symmetry,
These two equations are inseparable. You cannot solve the first for without already knowing , and vice versa. They form a system:
The off-diagonal couplings ARE the system
If the two equations decouple: and . We are back to two independent first-order ODEs, each solvable on its own. The whole interest of a system is in those off-diagonal terms and that wire the equations together.
Anatomy of a First-Order System
A system of n first-order ODEs in standard form looks like
Three properties are worth naming explicitly, because each of them changes the toolkit you reach for.
| Property | What it means | What changes if it fails |
|---|---|---|
| First-order | Only first derivatives y_i' appear on the left. | Higher orders can ALWAYS be reduced to first-order (see below), so this is no loss of generality. |
| Autonomous | t does not appear explicitly on the right: f_i = f_i(y_1, …, y_n). | If t appears explicitly we say the system is non-autonomous; the trick `set z = t` reduces this to an autonomous system one size larger. |
| Linear | Every f_i is a linear combination of the y_j's, possibly with t-dependent coefficients. | Nonlinear systems are the rule in nature (predator-prey, Lorenz, chemical reactors). They rarely have closed-form solutions and motivate the whole subject of phase-plane analysis. |
Why first-order matters
Every numerical solver in existence — Euler, RK4, scipy , MATLAB ode45, torchdiffeq, even the analog circuits in old wind-tunnel computers — consumes a first-order system. So before you can integrate anything, you must rewrite it in first-order form. This is not a quirk: a first-order system says "given the current state, here is the velocity", which is exactly the information you need to step forward.
The Vector Form
Stack the unknowns into a column vector and stack the right-hand sides into a vector-valued function . Then the entire system collapses to a single, beautiful line:
This is the master equation for the rest of the chapter. It looks identical to the scalar ODE you already know — and that is deliberate. Every theorem about scalar first-order ODEs (existence, uniqueness, slope fields, Euler's method, RK4, Picard iteration) carries over verbatim, with the single change that becomes a vector and becomes a vector field. That uniformity is the entire reason this notation is worth memorising.
Why the vector form pays off immediately
Reading aloud gives you the right mental picture: "at every point in state space, there is an arrow telling you the velocity of the state." The solution is the curve you trace when you start somewhere and let the arrows carry you forward in time. This is the geometric core of the phase-plane picture.
Linear Systems and the Matrix
When every right-hand side is a linear combination of the 's with constant coefficients, the system is linear with constant coefficients:
Stack the coefficients into a matrix and the system becomes
That is the equation that drives this entire chapter. It is the simplest possible system, and yet it already produces every flavour of behaviour we will study: decay, growth, oscillation, spiralling, saddles. The reason is that the matrix A is a stretching map on the velocity arrows: at state , the system velocity is . So the geometry of the trajectories is entirely encoded in the geometry of the matrix — eventually, in its eigenvalues and eigenvectors (section 23.2).
One equation. Three viewpoints.
- Component view: . Useful for paper-and-pencil and intuition.
- Vector-field view: with . Useful for theorems and code.
- Geometric view: a vector field in the (x, y)-plane whose arrows are . Useful for seeing what the solutions do.
The Phase Plane: A New Way to Look at Solutions
For a scalar ODE you plot against . For a 2-D system you have a choice. You can plot two time-series, and , side by side. Or you can do something far more revealing: throw away entirely and plot the curve
The plane is called the phase plane, and the curve is called the orbit or trajectory of the solution. Why is this view so useful? Because the system itself tells you, at every point in the plane, the direction the orbit must go: the velocity vector at is exactly . Draw those arrows on a grid and you get a vector field — every trajectory is just a curve tangent to that field at every point.
The phase plane turns "solve a system of ODEs" into "follow the arrows." It is the same idea as a wind map, where streamlines are exactly the paths a leaf would trace.
In higher dimensions the same picture lives in and is called phase space. The Lorenz system lives in and its phase-space orbit is the famous butterfly attractor. We will keep to for most of this chapter because it is the only case you can see.
Reduction: Every High-Order ODE Hides a System
Why do we focus on first-order systems? Because any higher-order ODE can be rewritten as one. This is the single most important trick in numerical ODEs.
Take the second-order spring-mass-damper equation
Introduce the new variable (velocity). Then , and the original equation becomes , i.e. . Together with the definition , we have a 2-D first-order system:
The same trick — "rename higher derivatives as new variables" — converts an -th order ODE into an -dimensional first-order system. The characteristic polynomial of the original ODE becomes the characteristic polynomial of : the roots of are exactly the roots of from section 22.1. We did not lose anything by going to a system — we just made the structure more uniform.
The unification
A scalar n-th order ODE, a system of first-order ODEs, and a linear operator on : these are three views of the same object. Each view is best for a different purpose. High-order ODEs are easiest to write down from physics. First-order systems are easiest to integrate numerically. Matrices are easiest to analyse with eigenvalues. Knowing how to translate between them is a superpower.
Existence and Uniqueness for Systems
The existence-and-uniqueness theorem for one ODE generalises without change to systems, once we replace scalar absolute values by vector norms.
Existence and uniqueness (system version)
Consider the initial-value problem
where is continuous in and Lipschitz in on a neighbourhood of . Then a unique solution exists on some open interval around .
Two facts follow immediately and are worth keeping in your head:
- A system of size needs exactly initial conditions — one per state variable. Two for a 2-D system; three for the Lorenz system; six for the position-plus-velocity of a particle in 3-D.
- For a linear system with constant, the right-hand side is globally Lipschitz, so the solution exists for all . No blow-up, ever. For nonlinear systems (predator-prey, Lorenz) the solution may only exist on a bounded interval.
Two orbits can never cross
Uniqueness has a striking geometric consequence in the phase plane: two distinct trajectories of an autonomous system can never cross. If they did, the crossing point would be a state from which two different futures emerge — violating uniqueness. This is the reason phase portraits look so organised: the orbits foliate the plane.
Worked Example (Step-by-Step)
Let us solve the 2-D linear system
We will derive the closed form by hand (so we have something to check our code against), and along the way we will preview the eigenvalue method that section 23.2 develops in full.
▶ Click to expand the full pen-and-paper derivation
Step 1 — Write the system in matrix form
Stack the unknowns into . Read off the coefficients to get
Step 2 — Try the exponential ansatz
Inspired by the success of for scalar linear ODEs, we guess for some constant vector and scalar . Then and . Cancel from both sides:
That is exactly the eigenvalue equation. So a system of linear ODEs reduces to a linear-algebra problem: find the eigenvalues and eigenvectors of .
Step 3 — Solve the characteristic polynomial
The eigenvalues come from :
Expand: , so , giving and . Both eigenvalues are real and negative — we will see in section 23.4 that this guarantees the origin is a stable node.
Step 4 — Find the eigenvectors
For solve :
For solve :
Step 5 — Write down the general solution
By linearity, any linear combination of the two modes is also a solution:
Step 6 — Apply the initial conditions
At : , i.e.
Step 7 — Final closed form
Step 8 — Spot-check numerically
At : , . So
You can verify these against the Python implementation below — both Euler with small and RK4 with larger reproduce them to several decimal places.
Step 9 — Read off the geometry
- The two modes have different time scales: the mode dies out faster than the mode.
- For large , the orbit aligns with the slow eigenvector — that is the direction the system approaches the origin from.
- For short times, the fast mode shapes the initial transient.
Interactive Phase-Portrait Explorer
Set the matrix with the sliders, drag the green dot anywhere in the plane to choose an initial condition, and watch the orange trajectory unroll. The blue arrows are the vector field ; the dashed lines (when eigenvalues are real) are the eigenlines — the special directions along which the system moves in a straight line. Try the presets at the bottom right to see all five qualitative flavours of linear systems we will study in the next sections.
What to look for
- With the default matrix (the one from our worked example), and . Both eigenvalues are negative ⇒ every trajectory funnels into the origin (stable node).
- Drag the green dot ONTO an eigenline (the green dashed lines). The orbit stays on that line and decays straight to the origin — no curving. That is what the exponential ansatz literally means.
- Try the Saddle preset (). One eigenvalue grows, one decays. Almost every orbit eventually shoots off along the unstable (red) eigenline.
- Try the Center preset (). Trajectories close into perfect ellipses — undamped oscillation, same as a frictionless spring.
A Nonlinear System: Predator and Prey
Linear systems are clean, but most of nature is nonlinear. The canonical example is the Lotka–Volterra model of prey and predator :
Notice the terms and : products of the two unknowns. That is what makes the system nonlinear, and it is also exactly what makes it biologically realistic. Predators eat prey at a rate proportional to how often they meet, and meetings happen in proportion to .
The same vector form still applies — the only thing that changes is that is no longer the linear map . There is no matrix to diagonalise, no closed-form solution. But the geometric picture is even richer: the orbits form closed loops, and the populations cycle forever in lockstep.
What the closed loops mean
A closed orbit in the phase plane is a periodic solution: the system returns to its starting state after a fixed time. The cycle of "rabbits multiply → foxes feast → rabbits crash → foxes starve → rabbits recover" is captured exactly by the loop. You will spend much of sections 23.7–23.8 understanding when, and why, nonlinear systems produce closed orbits.
Computation in Python: Integrating a System
Below is a complete Python implementation that integrates the linear system from the worked example two different ways — forward Euler with a tiny step, and classical RK4 with a 10× larger step — and compares both to the closed form we derived by hand. Every step is annotated; click any line in the code panel to see what it does.
Expected output
Running the script produces (your last-digit may differ due to floating-point):
RK4 max error in x: 7.1e-08 x(0.5) RK4: 1.4361914091 exact: 1.4361914796 y(0.5) RK4: 0.9899311094 exact: 0.9899311593
RK4 with is accurate to seven decimal places — and it ran 10× fewer steps than the Euler version. Higher-order solvers really do save you time.
PyTorch View: Matrix Exponentials for Linear Systems
For a constant-coefficient linear system , there is a beautiful closed form that requires no numerical integration:
where is the matrix exponential, defined by the same series as the scalar exponential
This is one of the reasons matrices are so powerful: every scalar identity for has a matrix analogue, and the entire theory of linear ODEs collapses into one line. In PyTorch the routine is and it runs on GPU; we use it as the exact reference solution.
exp vs matrix_exp
Never confuse the scalar with the matrix . The former acts elementwise; the latter is the genuine matrix exponential. Applying to a matrix would give you a matrix of elementwise exponentials — a totally different object that does not solve any ODE. This is the single most common bug when implementing continuous-time models.
Common Pitfalls
- Forgetting a coupling term. Writing instead of decouples the equations and silently turns your system into two independent ODEs. Always double-check that every state variable that should influence a derivative actually appears on the right.
- Wrong number of initial conditions. A 2-D system needs two; a 3-D system needs three. One ic per state component, no exceptions. If you write a 2-D system and only specify , the future is not determined.
- Solving variable-by-variable. A coupled system cannot be solved one variable at a time. You must step the entire vector forward together.
- Confusing scalar and matrix exp. For linear systems the closed form is with the matrix exponential — not the elementwise one.
- Euler step too big. Forward Euler is conditionally stable: if for some eigenvalue , the numerical solution diverges even when the true solution decays. For our worked example () this means . RK4 has a much larger stability region — one reason it is the default.
- Reading rows vs columns of A. A row of tells you how ONE variable is built from all the others. A column of tells you how ONE variable INFLUENCES the derivatives of all the others. These are dual perspectives — get used to switching between them.
Summary
- A system of first-order ODEs describes the joint evolution of several quantities and is written in compact form .
- Coupling lives in the off-diagonal dependences of on ; without it, the system is just several independent scalar ODEs.
- Any -th order ODE can be reduced to an -dimensional first-order system by naming each derivative as a new state variable.
- A linear constant-coefficient system has the form ; its geometry is entirely encoded in the eigenvalues and eigenvectors of .
- The phase plane turns the problem into following a vector field — orbits are tangent to everywhere, and uniqueness forbids them from crossing.
- A first-order system of size needs initial conditions; the existence-and-uniqueness theorem for one ODE generalises verbatim.
- Numerically, Euler and RK4 work line-for-line the same as in the scalar case — only now the state is a vector.
- For linear systems, the exact solution is with the matrix exponential — a single call to .
Next up (section 23.2) we make the eigenvalue method rigorous and learn to read the qualitative behaviour of any 2×2 linear system directly off its trace and determinant.