Runge-Kutta methods#

Runge-Kutta methods integrate an MPS-valued ordinary differential equation

\[\frac{d\psi}{dt} = F(t, \psi).\]

For runge_kutta() and runge_kutta_fehlberg(), the right-hand side can be provided either as an MPO or as a Python callable. If an MPO L is provided, the solver uses F(t, state) = L @ state. If a callable is provided, it must have the signature F(t, state) and return the MPS derivative at that point. This allows the same solvers to handle time-independent MPOs, time-dependent operators, and problem-specific PDE right-hand sides.

The order of the method determines the local truncation error and the number of operator applications required per step. Thus, it is important to consider the trade-off between cost and accuracy when choosing the most suitable method for each application.

The SeeMPS library considers four methods.

1. Euler method#

This is an explicit, first-order Taylor approximation of the evolution, with a simple update with a fixed time step.

\[\psi_{k+1} = \psi_k + \Delta t F(t_k, \psi_k).\]

2. Improved Euler or Heun method#

This is a second-order, fixed-step explicit method that uses two evaluations of the right-hand side and two linear combinations of states.

\[\begin{split}v_1 &= F(t_k, \psi_k), \\ v_2 &= F(t_k + \Delta t, \psi_k + \Delta t v_1), \\ \psi_{k+1} &= \psi_k + \frac{\Delta t}{2}(v_1 + v_2).\end{split}\]

3. Fourth-order Runge-Kutta method#

This algorithm uses four evaluations of the right-hand side and four linear combinations of states.

\[\begin{split}v_1 &= F(t_k, \psi_k), \\ v_2 &= F(t_k + \Delta t/2, \psi_k + \Delta t v_1/2), \\ v_3 &= F(t_k + \Delta t/2, \psi_k + \Delta t v_2/2), \\ v_4 &= F(t_k + \Delta t, \psi_k + \Delta t v_3), \\ \psi_{k+1} &= \psi_k + \frac{\Delta t}{6}(v_1 + 2v_2 + 2v_3 + v_4).\end{split}\]

4. Runge-Kutta-Fehlberg method#

The Runge-Kutta-Fehlberg algorithm is an adaptive step-size solver that combines two embedded Runge-Kutta formulas. This combination dynamically adjusts the step size to keep the integration error within a specified tolerance. Each attempted step evaluates the right-hand side six times, and the solver may repeat a step if the proposed step size is not suitable.

Examples#

Using a time-independent MPO:

final = runge_kutta(L, time=1.0, state=initial, steps=100)

Using a time-dependent or problem-specific operator:

def rhs(t, state):
    return diffusion_mpo(t) @ state + source(t, state)

final = runge_kutta_fehlberg(rhs, time=(0.0, 1.0), state=initial)

euler(L, time, state[, steps, strategy, ...])

Solve d|state>/dt = L|state> using the Euler method.

euler2(L, time, state[, steps, strategy, ...])

Solve d|state>/dt = L|state> using the 2nd order Euler method.

runge_kutta(L, time, state[, steps, ...])

Solve d|state>/dt = F(t, state) using a fourth order Runge-Kutta method.

runge_kutta_fehlberg(L, time, state[, ...])

Solve d|state>/dt = F(t, state) using a Runge-Kutta-Fehlberg method.

See also#