DQPT in the Ising model(@id demo_dqpt)

In this tutorial we will try to reproduce the results from this paper. The needed packages are

using MPSKit, MPSKitModels, TensorKit
using TensorOperations: TensorOperations;
TensorOperations.disable_cache(); # hide

Dynamical quantum phase transitions (DQPT in short) are signatures of equilibrium phase transitions in a dynamical quantity - the loschmidth echo. This quantity is given by $L(t) = \frac{-2}{N} ln(| < \psi(t) | \psi(0) > |)$ where $N$ is the system size. One typically starts from a groundstate and then quenches the hamiltonian to a different point. Non analycities in the loschmidth echo are called 'dynamical quantum phase transitions'.

In the mentioned paper they work with

$H(g) = - \sum^{N-1}_{i=1} \sigma^z_i \sigma^z_{i+1} + g \sum_{i=1}^N \sigma^x_i$

and show that divergences occur when quenching across the critical point (g₀ → g₁) for $t^*_n = t^*(n+\frac{1}{2})$ with $t^* = \pi/e(g_1,k^*)$, $cos(k^*) = (1+g_0 g_1) / (g_0 + g_1)$, $e(g,k) = \sqrt{(g-cos k)^2 + sin^2 k}$.

The outline of the tutorial is as follows. We will pick $g₀ = 0.5$, $g₁ = 2.0$, and perform the time evolution at different system sizes and compare with the thermodynamic limit. For those $g$ we expect non-analicities to occur at $t_n ≈ 2.35 (n + 1/2)$.

First we construct the hamiltonian in mpo form, and obtain the pre-quenched groundstate:

H₀ = transverse_field_ising(; g=-0.5)

L = 20
ψ₀ = FiniteMPS(rand, ComplexF64, L, ℂ^2, ℂ^10)
ψ₀, _ = find_groundstate(ψ₀, H₀, DMRG());
[ Info: Iteraton 0 error 0.06549008355303014
[ Info: Iteraton 1 error 3.8736052080636905e-5
[ Info: Iteraton 2 error 1.7276421455149173e-5
[ Info: Iteraton 3 error 4.6807658588611276e-8
[ Info: Iteraton 4 error 4.473231419129997e-11
[ Info: Iteraton 5 error 9.43878140025498e-13

Finite MPS quenching

We can define a helper function that measures the loschmith echo

echo(ψ₀::FiniteMPS, ψₜ::FiniteMPS) = -2 * log(abs(dot(ψ₀, ψₜ))) / length(ψ₀)
@assert isapprox(echo(ψ₀, ψ₀), 0, atol=1e-10)

We will initially use a two-site TDVP scheme to dynamically increase the bond dimension while time evolving, and later on switch to a faster one-site scheme. A single timestep can be done using

H₁ = transverse_field_ising(; g=-2.0)
ψₜ = deepcopy(ψ₀)
dt = 0.01
ψₜ, envs = timestep(ψₜ, H₁, dt, TDVP2(; trscheme=truncdim(20)));

"envs" is a kind of cache object that keeps track of all environments in ψ. It is often advantageous to re-use the environment, so that mpskit doesn't need to recalculate everything.

Putting it all together, we get

function finite_sim(L; dt=0.05, finaltime=5.0)
    ψ₀ = FiniteMPS(rand, ComplexF64, L, ℂ^2, ℂ^10)
    ψ₀, _ = find_groundstate(ψ₀, H₀, DMRG())

    ψₜ = deepcopy(ψ₀)
    envs = environments(ψₜ, H₁)

    echos = [echo(ψₜ, ψ₀)]
    times = collect(0:dt:finaltime)

    for t in times[2:end]
        alg = t > 3 * dt ? TDVP() : TDVP2(; trscheme=truncdim(50))
        ψₜ, envs = timestep(ψₜ, H₁, dt, alg, envs)
        push!(echos, echo(ψₜ, ψ₀))
    end

    return times, echos
end
finite_sim (generic function with 1 method)

Infinite MPS quenching

Similarly we could start with an initial infinite state and find the pre-quench groundstate:

ψ₀ = InfiniteMPS([ℂ^2], [ℂ^10])
ψ₀, _ = find_groundstate(ψ₀, H₀, VUMPS());
[ Info: vumps @iteration 1 galerkin = 0.06601870321517138
[ Info: vumps @iteration 2 galerkin = 2.2516739036323203e-5
[ Info: vumps @iteration 3 galerkin = 3.4932735965628556e-8
[ Info: vumps @iteration 4 galerkin = 1.1714311204809937e-9
[ Info: vumps @iteration 5 galerkin = 9.49274778774588e-11
[ Info: vumps @iteration 6 galerkin = 9.53461947599348e-12
[ Info: vumps @iteration 7 galerkin = 1.0106476372085772e-12
[ Info: vumps @iteration 8 galerkin = 1.2306829064204868e-13

The dot product of two infinite matrix product states scales as $\alpha ^N$ where $α$ is the dominant eigenvalue of the transfer matrix. It is this $α$ that is returned when calling

dot(ψ₀, ψ₀)
0.9999999999999998 + 7.851374352485397e-16im

so the loschmidth echo takes on the pleasant form

echo(ψ₀::InfiniteMPS, ψₜ::InfiniteMPS) = -2 * log(abs(dot(ψ₀, ψₜ)))
@assert isapprox(echo(ψ₀, ψ₀), 0, atol=1e-10)

This time we cannot use a two-site scheme to grow the bond dimension, as this isn't implemented (yet). Instead, we have to make use of the changebonds machinery. Multiple algorithms are available, but we will only focus on OptimalEpand(). Growing the bond dimension by $5$ can be done by calling:

ψₜ = deepcopy(ψ₀)
ψₜ, envs = changebonds(ψₜ, H₁, OptimalExpand(; trscheme=truncdim(5)));

a single timestep is easy

dt = 0.01
ψₜ, envs = timestep(ψₜ, H₁, dt, TDVP(), envs);

With performance in mind we should once again try to re-use these "envs" cache objects. The final code is

function infinite_sim(dt=0.05, finaltime=5.0)
    ψ₀ = InfiniteMPS([ℂ^2], [ℂ^10])
    ψ₀, _ = find_groundstate(ψ₀, H₀, VUMPS())

    ψₜ = deepcopy(ψ₀)
    envs = environments(ψₜ, H₁)

    echos = [echo(ψₜ, ψ₀)]
    times = collect(0:dt:finaltime)

    for t in times[2:end]
        if t < 50dt # if t is sufficiently small, we increase the bond dimension
            ψₜ, envs = changebonds(ψₜ, H₁, OptimalExpand(; trscheme=truncdim(1)), envs)
        end
        (ψₜ, envs) = timestep(ψₜ, H₁, dt, TDVP(), envs)
        push!(echos, echo(ψₜ, ψ₀))
    end

    return times, echos
end
infinite_sim (generic function with 3 methods)


This page was generated using Literate.jl.