viva_math/ode

Numerical ODE / SDE solvers.

Single-step integrators for scalar systems dx/dt = f(t, x) and stochastic systems dx = f(t, x) dt + g(t, x) dW. Step functions are pure: they take the current (t, x) and produce the next state.

Methods

FunctionOrderUse case
euler1Quick, stiff systems with small dt
rk2_midpoint2Mid-accuracy, half the cost of RK4
rk2_heun2Trapezoidal/improved Euler
rk44Workhorse for non-stiff systems
euler_maruyama0.5*SDE with additive noise (* strong order)
milstein1.0*SDE with multiplicative noise

For full trajectories use integrate / integrate_sde.

Types

Diffusion function g(t, x) for SDEs.

pub type Diffusion =
  fn(Float, Float) -> Float

Drift function f(t, x).

pub type Drift =
  fn(Float, Float) -> Float

Force law F(q): acceleration as a function of position (unit mass).

pub type ForceLaw =
  fn(Float) -> Float

Values

pub fn dop54(
  f: fn(Float, Float) -> Float,
  t: Float,
  x: Float,
  dt: Float,
) -> #(Float, Float)

One step of Dormand-Prince 5(4) with embedded error estimate.

Returns #(x_new, err) where x_new is the 5th-order solution and err is the absolute difference from the embedded 4th-order estimate, suitable for step-size control. Per-step truncation error is O(dt⁶).

pub fn euler(
  f: fn(Float, Float) -> Float,
  t: Float,
  x: Float,
  dt: Float,
) -> Float

Euler step: xₙ₊₁ = xₙ + dt · f(tₙ, xₙ).

pub fn euler_maruyama(
  f: fn(Float, Float) -> Float,
  g: fn(Float, Float) -> Float,
  t: Float,
  x: Float,
  dt: Float,
  seed: random.Seed,
) -> #(Float, random.Seed)

Euler-Maruyama step for dx = f dt + g dW with normal increment dW = √dt·Z.

Returns the new state and the advanced PRNG seed.

pub fn integrate(
  method: fn(fn(Float, Float) -> Float, Float, Float, Float) -> Float,
  f: fn(Float, Float) -> Float,
  t0: Float,
  x0: Float,
  dt: Float,
  steps: Int,
) -> List(#(Float, Float))

Integrate a deterministic ODE with a fixed-step method.

pub fn integrate_sde(
  f: fn(Float, Float) -> Float,
  g: fn(Float, Float) -> Float,
  t0: Float,
  x0: Float,
  dt: Float,
  steps: Int,
  seed: random.Seed,
) -> #(List(#(Float, Float)), random.Seed)

Integrate a stochastic system with Euler-Maruyama.

pub fn integrate_symplectic(
  method: fn(fn(Float) -> Float, Float, Float, Float) -> #(
    Float,
    Float,
  ),
  force: fn(Float) -> Float,
  t0: Float,
  q0: Float,
  v0: Float,
  dt: Float,
  steps: Int,
) -> List(#(Float, Float, Float))

Integrate a Hamiltonian system with a symplectic method.

pub fn leapfrog(
  force: fn(Float) -> Float,
  q: Float,
  v: Float,
  dt: Float,
) -> #(Float, Float)

Leapfrog (kick-drift-kick) — order 2, symplectic.

pub fn milstein(
  f: fn(Float, Float) -> Float,
  g: fn(Float, Float) -> Float,
  dg_dx: fn(Float, Float) -> Float,
  t: Float,
  x: Float,
  dt: Float,
  seed: random.Seed,
) -> #(Float, random.Seed)

Milstein step — corrects Euler-Maruyama with the Itô derivative of g.

dx = f dt + g dW + ½g·g’(t,x)·(dW² - dt)

dg_dx is the partial derivative ∂g/∂x. If g doesn’t depend on x (additive noise), use euler_maruyama instead — they coincide.

pub fn position_verlet(
  force: fn(Float) -> Float,
  q_prev: Float,
  q: Float,
  dt: Float,
) -> Float

Position Verlet — q(t+dt) = 2·q(t) - q(t-dt) + a(q(t))·dt².

pub fn rk2_heun(
  f: fn(Float, Float) -> Float,
  t: Float,
  x: Float,
  dt: Float,
) -> Float

Heun (improved Euler) RK2: trapezoidal predictor-corrector.

pub fn rk2_midpoint(
  f: fn(Float, Float) -> Float,
  t: Float,
  x: Float,
  dt: Float,
) -> Float

Midpoint Runge-Kutta (RK2): evaluates f at the half-step midpoint.

pub fn rk4(
  f: fn(Float, Float) -> Float,
  t: Float,
  x: Float,
  dt: Float,
) -> Float

Classical 4th-order Runge-Kutta.

pub fn rkf45(
  f: fn(Float, Float) -> Float,
  t: Float,
  x: Float,
  dt: Float,
) -> #(Float, Float)

Deprecated alias retained for backwards compatibility. Returns the same pair as dop54. To be removed once external callers migrate. One step of RKF45 with an error estimate.

Returns #(x5, error) where x5 is the 5th-order estimate and error is |x5 - x4|, useful for step-size control.

pub fn velocity_verlet(
  force: fn(Float) -> Float,
  q: Float,
  v: Float,
  dt: Float,
) -> #(Float, Float)

Velocity Verlet — order 2, symplectic, time-reversible.

pub fn yoshida4(
  force: fn(Float) -> Float,
  q: Float,
  v: Float,
  dt: Float,
) -> #(Float, Float)

Yoshida 4th-order symplectic integrator.

Composes three leapfrog steps with Yoshida (1990) coefficients. Order 4 global error, ~3× the cost of leapfrog per step but allows ~10× larger dt for the same accuracy.

Search Document