Skip to content

time_evolve

Computes the real-time evolution,

\[\vert \psi(t) \rangle = e^{-iHt} \vert \psi_0\rangle,\]

of a State \(\vert \psi_0 \rangle\) and a Hermitian operator \(H\) using an iterative algorithm.

The algorithm can be run either on-the-fly (matrix-free) or using a sparse matrix in the compressed-sparse-row format (see CSRMatrix).

Sources
time_evolve.hpp
time_evolve.cpp
time_evolve.jl


Definition

On-the-fly

The method is provided in two variants:

  1. Returning a new state while the input state remains untouched. This variant is safe to use and simple to code.

    State time_evolve(OpSum const &H, State psi0, double time,
                      double precision = 1e-12,
                      std::string algorithm = "lanczos");
    
    time_evolve(H::OpSum, psi0::State, time::Float64; 
                precision::Float64 = 1e-12, 
                algorithm::String = "lanczos")::State
    
  2. An inplace variant time_evolve_inplace, where the input state is overwritten and contains the time evolved state upon exit. This version is more memory efficient than time_evolve.

    void time_evolve_inplace(OpSum const &H, State &psi0, double time,
                             double precision = 1e-12,
                             std::string algorithm = "lanczos");
    
    time_evolve_inplace(H::OpSum, psi0::State, time::Float64; 
                        precision::Float64 = 1e-12, 
                        algorithm::String = "lanczos")
    

Sparse matrix

  1. Returning a new state while the input state remains untouched. This variant is safe to use and simple to code.

    template <typename idx_t, typename coeff_t>
    State time_evolve(CSRMatrix<idx_t, coeff_t> const &H, State psi,
        double time, double precision = 1e-12,
        std::string algorithm = "lanczos");
    
    time_evolve(ops::CSRMatrix, psi0::State, time::Float64; 
        precision::Float64 = 1e-12, 
        algorithm::String = "lanczos")::State
    
  2. An inplace variant time_evolve_inplace, where the input state is overwritten and contains the time evolved state upon exit. This version is more memory efficient than time_evolve.

    template <typename idx_t, typename coeff_t>
    void time_evolve_inplace(CSRMatrix<idx_t, coeff_t> const &H,
        State &psi, double time, double precision = 1e-12,
        std::string algorithm = "lanczos");
    
    time_evolve_inplace(ops::CSRMatrix, psi0::State, time::Float64; 
        precision::Float64 = 1e-12, algorithm::String = "lanczos")
    

Parameters

Name Description Default
H OpSum or CSRMatrix defining the hermitian operator \(H\) for time evolution
psi0 initial State \(\vert \psi_0 \rangle\) of the time evolution
time time \(t\) until which the state is evolved
precision accuracy of the computed time evolved state \(\vert \psi(t) \rangle\) 1e-12
algorithm iterative algorithm which is used, one of lanczos or expokit lanczos

The algorithm parameter decised which backend is run. If lanczos is chosen, the evolve_lanczos routine is called with the standard arguments. Alternatively, expokit chooses the time_evolve_expokit routine. For a detailed documentation of the algorithms we refer to the evolve_lanczos and time_evolve_expokit pages. Broadly speaking, the expokit can yield higher precision states at arbitrarily long times at the cost of increased memory and computing time. In practice, we recommend analysing the effect of the precision parameters on the time evolution series obtained in both cases.


Usage Example

int N = 8;
int nup = N / 2;
auto block = Spinhalf(N, nup);

// Define the nearest-neighbor Heisenberg model
auto ops = OpSum();
for (int i=0; i<N; ++i) {
  ops += Op("SdotS", {i, (i+1) % N});
}

auto psi0 = product_state(block, {"Up", "Dn", "Up", "Dn", "Up", "Dn", "Up", "Dn"});
double time = 1.0;

// On-the-fly
auto psi = time_evolve(ops, psi0, time);
time_evolve_inplace(ops, psi0, time);
XDIAG_SHOW(isapprox(psi0, psi));

// sparse matrix
auto spmat = csr_matrix(ops, block);
auto psis = time_evolve(spmat, psi0, time);
let
    N = 8
    nup = N รท 2
    block = Spinhalf(N, nup)

    # Define the nearest-neighbor Heisenberg model
    ops = OpSum()
    for i in 1:N
        ops += "J" * Op("SdotS", [i, mod1(i+1, N)])
    end
    ops["J"] = 1.0

    psi0 = product_state(block, ["Up", "Dn", "Up", "Dn", "Up", "Dn", "Up", "Dn"])
    time = 1.0

    # on-the-fly
    psi = time_evolve(ops, psi0, time)
    time_evolve_inplace(ops, psi0, time)
    @show isapprox(psi0, psi)

    # sparse matrix
    spmat = csr_matrix(ops, block)
    psi = time_evolve(spmat, psi0, time)
end