Article Physics & Mechanics · ≈ ⏱ 10 min read

Leapfrog symplecticity: a proof, and why it bounds energy error forever

"Symplectic" is thrown around a lot in physics-engine articles, rarely proven. Here we derive, step by step, why the Leapfrog / Störmer-Verlet map exactly preserves the symplectic 2-form (a quantity that measures oriented area in phase space and stays constant under exact Hamiltonian motion) — and what that buys you: no secular energy drift, even after a billion steps.

TL;DR: Leapfrog (Störmer-Verlet) can be split into Drift-Kick-Drift sub-steps whose Jacobians each have determinant exactly 1, so their composition preserves phase-space area exactly, step after step. That's why Leapfrog's energy error stays bounded and oscillates, rather than drifting away like RK4's does over long simulations.

1. What "symplectic" means

Гамільтонова система еволюціонує у фазовому просторі (q, p) (координати, імпульси). Симплектична форма — це білінійна антисиметрична 2-форма ω = dq ∧ dp, яка вимірює орієнтовану площу в фазовому просторі. Потік φₜ точних рівнянь Гамільтона зберігає цю форму точно: φₜ* ω = ω для будь-якого t.

Symplectic condition (matrix form) Jᵀ · Ω · J = Ω,    де Ω = [[0, I], [−I, 0]]

Тут J = ∂(q', p')/∂(q, p) — якобіан відображення одного кроку в фазовому просторі. Це узагальнення умови det J = 1 (збереження об'єму, теорема Ліувілля) — симплектичність строгіша: вона зберігає орієнтовану площу для кожної 2-площини, не лише повний об'єм.

Consequence we care about

Симплектичні інтегратори точно розв'язують «збурений гамільтоніан» H̃ = H + O(dtᵏ), близький до справжнього H. Тому похибка енергії обмежена й коливається навколо нуля, а не накопичується систематично, як в несимплектичних методах (Euler, RK4).

2. Leapfrog as a composition of maps

Розкладемо Leapfrog (DKD-форма) на три елементарні відображення фазового простору:

Drift-Kick-Drift as three maps Φ_D(h/2): q → q + p·(h/2)/m,   p незмінне
Φ_K(h): p → p + F(q)·h,   q незмінне
Φ_D(h/2): q → q + p·(h/2)/m,   p незмінне

Leapfrog = Φ_D(h/2) ∘ Φ_K(h) ∘ Φ_D(h/2)

Ключова ідея доведення: кожне з трьох відображень окремо симплектичне, а композиція симплектичних відображень завжди симплектична (це випливає з ланцюгового правила для якобіанів: J_composite = J₁·J₂·J₃, і якщо кожне Jᵢᵀ·Ω·Jᵢ = Ω, то й добуток задовольняє те саме).

3. Computing the Jacobian of Drift and Kick

Розглянемо 1D-систему (q, p) для простоти; узагальнення на багато вимірів — покомпонентне. Якобіан Drift-кроку:

Drift Jacobian J_D = [[∂q'/∂q, ∂q'/∂p], [∂p'/∂q, ∂p'/∂p]] = [[1, h/(2m)], [0, 1]]

Якобіан Kick-кроку (де сила F(q) залежить лише від позиції — типово для консервативних потенціалів):

Kick Jacobian J_K = [[1, 0], [h·F'(q), 1]]

Обидві матриці мають детермінант точно 1 — необхідна (але не достатня) умова симплектичності в 1D.

4. The proof: each map preserves ω

У 1D симплектична умова спрощується до det(J) = 1 (в одновимірному фазовому просторі 2×2 симплектична форма — це просто орієнтована площа). Перевіримо для Drift:

det(J_D) = 1 det [[1, h/(2m)], [0, 1]] = 1·1 − (h/(2m))·0 = 1 ✓

Аналогічно для Kick:

det(J_K) = 1 det [[1, 0], [h·F'(q), 1]] = 1·1 − 0·h·F'(q) = 1 ✓

Оскільки детермінант добутку матриць дорівнює добутку детермінантів:

Composite determinant det(J_D · J_K · J_D) = det(J_D) · det(J_K) · det(J_D) = 1·1·1 = 1 ∎

Це доводить, що кожен крок Leapfrog зберігає орієнтовану площу фазового простору точно — незалежно від dt, від нелінійності сили F(q), і без жодного наближення. На відміну від Euler чи RK4, тут немає похибки, яка накопичується — умова виконується рівно, аналітично.

Multi-dimensional generalization

У багатовимірному фазовому просторі (N частинок, 6N вимірів) аргумент той самий, лише детермінант замінюється повною симплектичною умовою Jᵀ·Ω·J = Ω на блочно-діагональних матрицях J_D, J_K. Кожен блок — це та сама 2×2 структура для кожної координати, тому доведення масштабується без змін.

5. Backward error analysis

Найглибший результат теорії симплектичних інтеграторів (Hairer, Lubich, Wanner) — backward error analysis: симплектичний метод точно розв'язує «збурений» гамільтоніан H̃ = H + h²·H₂ + h⁴·H₄ + … для деякої обчислюваної H₂, H₄, … Оскільки H̃ — це справжня консервативна система (сама симплектична), її енергія зберігається точно.

Energy error bound (exponentially long, not forever) |H(t) − H(0)| = O(hᵖ),   для t ≤ exp(c/h)

«Назавжди» — це трохи перебільшення: похибка обмежена лише на експоненційно довгому проміжку часу (за теоремою KAM/backward-error), але для практичних симуляцій (мільйони — мільярди кроків N-тіл) це фактично невідрізнено від «завжди».

6. Why RK4 is not symplectic

RK4 обчислює зважене середнє чотирьох оцінок похідної в різних точках — це відображення фазового простору не факторизується у послідовність канонічних (симплектичних) перетворень. Якобіан RK4-кроку не задовольняє Jᵀ·Ω·J = Ω за жодного вибору dt (окрім тривіального dt → 0). Це можна перевірити прямим обчисленням якобіана для простого гармонічного осцилятора — det(J_RK4) ≠ 1 при скінченному h.

What this looks like in practice

Симулюйте орбіту Кеплера з RK4 на мільйон кроків — енергія систематично «повзе» в один бік (найчастіше зростає), орбіта поступово розкручується назовні. З Leapfrog енергія коливається в межах O(h²) навколо істинного значення без систематичного дрейфу.

7. Consequences compared

Property Leapfrog RK4
det(J) per step Exactly 1 ≠ 1 for finite h
Energy error over time Bounded oscillation Secular drift
Order of accuracy O(h²) O(h⁴)
Force evaluations/step 1 4
Best for Long-horizon N-body, MD Short, high-precision trajectories

8. Псевдокод

Verifying det(J) numerically (JS)

// Чисельна перевірка det(J) = 1 для одного кроку Leapfrog
// на простому гармонічному осциляторі F(q) = −k·q
function leapfrogJacobianDeterminant(k, m, h) {
  // Drift: q' = q + p*(h/2)/m, p' = p
  const Jd = [[1, h / (2 * m)], [0, 1]];
  // Kick: p' = p + F(q)*h = p − k*q*h, q' = q  → F'(q) = −k
  const Jk = [[1, 0], [−k * h, 1]];

  matMul2 = (A, B) => [
    [A[0][0]*B[0][0] + A[0][1]*B[1][0], A[0][0]*B[0][1] + A[0][1]*B[1][1]],
    [A[1][0]*B[0][0] + A[1][1]*B[1][0], A[1][0]*B[0][1] + A[1][1]*B[1][1]]
  ];

  const J = matMul2(matMul2(Jd, Jk), Jd);
  const det = J[0][0]*J[1][1] − J[0][1]*J[1][0];
  return det; // always exactly 1, for any k, m, h
}
▶ Live Demo

See long-term stability in action

Симуляція N-тіл цього проєкту використовує Leapfrog саме заради цієї властивості — орбіти залишаються стабільними навіть після десятків тисяч кроків.

⭐ N-Body Gravity 🔵 Molecular Dynamics

🔗 Related Simulations

N-Body 🔵Molecular Dynamics ⚙️Pendulum