Low rank master equation

We start by importing the packages

using QuantumToolbox
using CairoMakie
CairoMakie.enable_only_mime!(MIME"image/svg+xml"())

Define lattice

Nx, Ny = 2, 3
latt = Lattice(Nx = Nx, Ny = Ny)
Lattice{Int64, LinearIndices{2, Tuple{Base.OneTo{Int64}, Base.OneTo{Int64}}}, CartesianIndices{2, Tuple{Base.OneTo{Int64}, Base.OneTo{Int64}}}}(2, 3, 6, [1 3 5; 2 4 6], CartesianIndices((2, 3)))

Define lr-space dimensions

N_cut = 2         # Number of states of each mode
N_modes = latt.N  # Number of modes
N = N_cut^N_modes # Total number of states
M = Nx * Ny + 1       # Number of states in the LR basis
7

Define lr states. Take as initial state all spins up. All other N states are taken as those with miniman Hamming distance to the initial state.

ϕ = Vector{QuantumObject{Vector{ComplexF64},KetQuantumObject}}(undef, M)
ϕ[1] = kron(repeat([basis(2, 0)], N_modes)...)

global i = 1
for j in 1:N_modes
    global i += 1
    i <= M && (ϕ[i] = mb(sp, j, latt) * ϕ[1])
end
for k in 1:N_modes-1
    for l in k+1:N_modes
        global i += 1
        i <= M && (ϕ[i] = mb(sp, k, latt) * mb(sp, l, latt) * ϕ[1])
    end
end
for i in i+1:M
    ϕ[i] = QuantumObject(rand(ComplexF64, size(ϕ[1])[1]), dims = ϕ[1].dims)
    normalize!(ϕ[i])
end

Define the initial state

z = hcat(broadcast(x -> x.data, ϕ)...)
p0 = 0.0 # Population of the lr states other than the initial state
B = Matrix(Diagonal([1 + 0im; p0 * ones(M - 1)]))
S = z' * z # Overlap matrix
B = B / tr(S * B) # Normalize B

ρ = QuantumObject(z * B * z', dims = ones(Int, N_modes) * N_cut); # Full density matrix
Quantum Object:   type=Operator   dims=[2, 2, 2, 2, 2, 2]   size=(64, 64)   ishermitian=true
64×64 Matrix{ComplexF64}:
 1.0+0.0im  0.0+0.0im  0.0+0.0im  …  0.0+0.0im  0.0+0.0im  0.0+0.0im
 0.0+0.0im  0.0+0.0im  0.0+0.0im     0.0+0.0im  0.0+0.0im  0.0+0.0im
 0.0+0.0im  0.0+0.0im  0.0+0.0im     0.0+0.0im  0.0+0.0im  0.0+0.0im
 0.0+0.0im  0.0+0.0im  0.0+0.0im     0.0+0.0im  0.0+0.0im  0.0+0.0im
 0.0+0.0im  0.0+0.0im  0.0+0.0im     0.0+0.0im  0.0+0.0im  0.0+0.0im
 0.0+0.0im  0.0+0.0im  0.0+0.0im  …  0.0+0.0im  0.0+0.0im  0.0+0.0im
 0.0+0.0im  0.0+0.0im  0.0+0.0im     0.0+0.0im  0.0+0.0im  0.0+0.0im
 0.0+0.0im  0.0+0.0im  0.0+0.0im     0.0+0.0im  0.0+0.0im  0.0+0.0im
 0.0+0.0im  0.0+0.0im  0.0+0.0im     0.0+0.0im  0.0+0.0im  0.0+0.0im
 0.0+0.0im  0.0+0.0im  0.0+0.0im     0.0+0.0im  0.0+0.0im  0.0+0.0im
    ⋮                             ⋱                        
 0.0+0.0im  0.0+0.0im  0.0+0.0im  …  0.0+0.0im  0.0+0.0im  0.0+0.0im
 0.0+0.0im  0.0+0.0im  0.0+0.0im     0.0+0.0im  0.0+0.0im  0.0+0.0im
 0.0+0.0im  0.0+0.0im  0.0+0.0im     0.0+0.0im  0.0+0.0im  0.0+0.0im
 0.0+0.0im  0.0+0.0im  0.0+0.0im     0.0+0.0im  0.0+0.0im  0.0+0.0im
 0.0+0.0im  0.0+0.0im  0.0+0.0im     0.0+0.0im  0.0+0.0im  0.0+0.0im
 0.0+0.0im  0.0+0.0im  0.0+0.0im  …  0.0+0.0im  0.0+0.0im  0.0+0.0im
 0.0+0.0im  0.0+0.0im  0.0+0.0im     0.0+0.0im  0.0+0.0im  0.0+0.0im
 0.0+0.0im  0.0+0.0im  0.0+0.0im     0.0+0.0im  0.0+0.0im  0.0+0.0im
 0.0+0.0im  0.0+0.0im  0.0+0.0im     0.0+0.0im  0.0+0.0im  0.0+0.0im

Define the Hamiltonian and collapse operators

# Define Hamiltonian and collapse operators
Jx = 0.9
Jy = 1.04
Jz = 1.0
hx = 0.0
γ = 1

Sx = sum([mb(sx, i, latt) for i in 1:latt.N])
Sy = sum([mb(sy, i, latt) for i in 1:latt.N])
Sz = sum([mb(sz, i, latt) for i in 1:latt.N])
SFxx = sum([mb(sx, i, latt) * mb(sx, j, latt) for i in 1:latt.N for j in 1:latt.N])

H, c_ops = TFIM(Jx, Jy, Jz, hx, γ, latt; bc = pbc, order = 1)
e_ops = (Sx, Sy, Sz, SFxx)

tl = LinRange(0, 10, 100);
100-element LinRange{Float64, Int64}:
 0.0, 0.10101, 0.20202, 0.30303, 0.40404, …, 9.69697, 9.79798, 9.89899, 10.0

Full evolution

@time mesol = mesolve(H, ρ, tl, c_ops; e_ops = [e_ops...]);
A = Matrix(mesol.states[end].data)
λ = eigvals(Hermitian(A))
Strue = -sum(λ .* log2.(λ)) / latt.N;
0.29324728062546734

Low Rank evolution

Define functions to be evaluated during the low-rank evolution

function f_purity(p, z, B)
    N = p.N
    M = p.M
    S = p.S
    T = p.temp_MM

    mul!(T, S, B)
    return tr(T^2)
end

function f_trace(p, z, B)
    N = p.N
    M = p.M
    S = p.S
    T = p.temp_MM

    mul!(T, S, B)
    return tr(T)
end

function f_entropy(p, z, B)
    C = p.A0
    σ = p.Bi

    mul!(C, z, sqrt(B))
    mul!(σ, C', C)
    λ = eigvals(Hermitian(σ))
    λ = λ[λ.>1e-10]
    return -sum(λ .* log2.(λ))
end;
f_entropy (generic function with 1 method)

Define the options for the low-rank evolution

opt =
    LRMesolveOptions(err_max = 1e-3, p0 = 0.0, atol_inv = 1e-6, adj_condition = "variational", Δt = 0.0);

@time lrsol = lr_mesolve(H, z, B, tl, c_ops; e_ops = e_ops, f_ops = (f_purity, f_entropy, f_trace), opt = opt);
LRTimeEvolutionSol{Vector{Float64}, Vector{Base.ReshapedArray{ComplexF64, 2, SubArray{ComplexF64, 1, Vector{ComplexF64}, Tuple{UnitRange{Int64}}, true}, Tuple{}}}, Matrix{ComplexF64}, Vector{Int64}}([0.0, 0.10101010101010102, 0.20202020202020204, 0.30303030303030304, 0.4040404040404041, 0.5050505050505051, 0.6060606060606061, 0.7070707070707071, 0.8080808080808082, 0.9090909090909092  …  9.09090909090909, 9.191919191919192, 9.292929292929292, 9.393939393939394, 9.494949494949495, 9.595959595959595, 9.696969696969697, 9.797979797979798, 9.8989898989899, 10.0], Base.ReshapedArray{ComplexF64, 2, SubArray{ComplexF64, 1, Vector{ComplexF64}, Tuple{UnitRange{Int64}}, true}, Tuple{}}[[0.9758701452082731 - 0.0062733354161566895im 4.510861183912585e-6 - 1.2744772951808019e-6im … 7.212734624748742e-5 - 6.749597198527093e-5im 3.20473444597687e-5 - 7.751644610405045e-6im; 6.851797858602926e-5 + 8.432350838029289e-5im 0.002206702566450311 - 0.009972902494217093im … -0.030991584184361962 - 0.010275835891833408im -0.0194469365337664 - 0.002060674570893421im; … ; -4.375082399082003e-6 - 2.833841887293491e-5im -0.012542614242382177 - 0.00552167076726183im … 0.014889313568266367 - 0.010703192229961845im 0.004840160230242516 - 0.009187383691135675im; 0.002457947745352884 - 0.005900035456767583im -1.793956725599693e-5 + 9.601633880021862e-6im … -6.562146296634411e-5 - 1.795700509168489e-5im -1.8862875022214825e-5 + 3.2482148860781236e-6im]], Base.ReshapedArray{ComplexF64, 2, SubArray{ComplexF64, 1, Vector{ComplexF64}, Tuple{UnitRange{Int64}}, true}, Tuple{}}[[0.6675325020615186 - 1.0616060323828477e-27im -1.3174997938171626e-6 + 6.759872070946733e-7im … 1.4276461743567352e-5 - 1.0358985818398855e-5im 2.278850955022823e-6 - 1.5899424870488485e-6im; -1.3174997938171626e-6 - 6.759872070946733e-7im 0.0405772013740091 - 6.45316918993882e-29im … 3.0946858340803727e-6 - 2.4293178392662963e-5im -1.2768594359692596e-5 + 1.6686092142703284e-5im; … ; 1.4276461743567352e-5 + 1.0358985818398855e-5im 3.0946858340803727e-6 + 2.4293178392662963e-5im … 0.0003167952000393788 - 5.038132141178372e-31im 3.6097666323849403e-6 + 2.7262175839185744e-6im; 2.278850955022823e-6 + 1.5899424870488485e-6im -1.2768594359692596e-5 - 1.6686092142703284e-5im … 3.6097666323849403e-6 - 2.7262175839185744e-6im 0.00031669933635047757 - 5.036607579151658e-31im]], ComplexF64[0.0 + 0.0im 0.0 + 0.0im … 2.675736707339932e-6 + 1.0842021724855044e-19im 2.626355994970954e-6 + 2.5478751053409354e-18im; 0.0 + 0.0im 0.0 + 0.0im … -4.358957332674059e-6 + 9.75781955236954e-19im -4.245703296094618e-6 + 7.047314121155779e-19im; -6.0 + 0.0im -5.987982183309875 - 1.8243808117344763e-19im … -4.564264440513195 - 5.984795992119984e-17im -4.564346308946966 + 6.331740687315346e-17im; 6.0 + 0.0im 6.013514592692536 - 3.8194631541223296e-17im … 8.148097136596727 + 2.914335439641036e-16im 8.147991587776714 - 7.7021722333370235e-16im], ComplexF64[1.0 + 0.0im 0.9995913405802062 + 1.1922112809822968e-38im … 0.5162584310494549 + 4.957616476327083e-18im 0.5162816729137988 + 2.748200185908713e-18im; -0.0 + 0.0im 0.0031973769163574704 + 0.0im … 1.7339148149931138 + 0.0im 1.7338312081084286 + 0.0im; 1.0 + 0.0im 1.0 + 5.877471754111438e-39im … 1.0 - 2.1804115420308766e-27im 0.9999999999999999 - 1.9658413758107614e-27im], [7, 7, 7, 7, 7, 7, 7, 8, 15, 17  …  36, 36, 36, 36, 36, 36, 36, 36, 36, 36])

Plot the results

m_me = real(mesol.expect[3, :]) / Nx / Ny
m_lr = real(lrsol.expvals[3, :]) / Nx / Ny

fig = Figure(size = (500, 350), fontsize = 15)
ax = Axis(fig[1, 1], xlabel = L"\gamma t", ylabel = L"M_{z}", xlabelsize = 20, ylabelsize = 20)
lines!(ax, tl, m_lr, label = L"LR $[M=M(t)]$", linewidth = 2)
lines!(ax, tl, m_me, label = "Fock", linewidth = 2, linestyle = :dash)
axislegend(ax, position = :rb)

ax2 = Axis(fig[1, 2], xlabel = L"\gamma t", ylabel = "Value", xlabelsize = 20, ylabelsize = 20)
lines!(ax2, tl, 1 .- real(lrsol.funvals[1, :]), label = L"$1-P$", linewidth = 2)
lines!(
    ax2,
    tl,
    1 .- real(lrsol.funvals[3, :]),
    label = L"$1-\mathrm{Tr}(\rho)$",
    linewidth = 2,
    linestyle = :dash,
    color = :orange,
)
lines!(ax2, tl, real(lrsol.funvals[2, :]) / Nx / Ny, color = :blue, label = L"S", linewidth = 2)
hlines!(ax2, [Strue], color = :blue, linestyle = :dash, linewidth = 2, label = L"S^{\,\mathrm{true}}_{\mathrm{ss}}")
axislegend(ax2, position = :rb)

fig
Example block output