Dynamics and QuantumOptics.jl - Stefan Krastanov

This package should be thought of as a domain specific linear algebra wrapper.

Operator basics

using QuantumOpticsBase

cutoff = 25

F = FockBasis(cutoff)

Ψ = fockstate(F,5)
Ket(dim=26)
  basis: Fock(cutoff=25)
 0.0 + 0.0im
 0.0 + 0.0im
 0.0 + 0.0im
 0.0 + 0.0im
 0.0 + 0.0im
 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
S = SpinBasis(1//2)
s = spindown(S)
Ket(dim=2)
  basis: Spin(1/2)
 0.0 + 0.0im
 1.0 + 0.0im
G = GenericBasis(100)
basisstate(G,2)
Ket(dim=100)
  basis: Basis(dim=100)
 0.0 + 0.0im
 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
C = F ⊗ S

sparse(dm(Ψ⊗s))
Operator(dim=52x52)
  basis: [Fock(cutoff=25) ⊗ Spin(1/2)]
⎡⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎤
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎣⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎦
projector(Ψ⊗s)
Operator(dim=52x52)
  basis: [Fock(cutoff=25) ⊗ Spin(1/2)]
 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  0.0+0.0im
using BenchmarkTools
P = projector(Ψ)
Ps = sparse(P)

@benchmark P*Ψ
BenchmarkTools.Trial: 10000 samples with 310 evaluations per sample.
 Range (minmax):  270.761 ns 27.236 μs   GC (min … max): 0.00% … 97.88%
 Time  (median):     274.900 ns                GC (median):    0.00%
 Time  (mean ± σ):   306.462 ns ± 355.662 ns   GC (mean ± σ):  6.43% ±  8.58%

  ▁        ▂                                                 ▁
  █▇▅▄▃▃▃▁██▇▇▅▁▄▁▁▁▃▁▁▁▁▁▁▁▁▄▄▅▃▅▃▄▃▁▁▁▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▃▆▅ █
  271 ns        Histogram: log(frequency) by time       1.28 μs <

 Memory estimate: 528 bytes, allocs estimate: 3.
@benchmark Ps*Ψ
BenchmarkTools.Trial: 10000 samples with 966 evaluations per sample.
 Range (minmax):   80.233 ns 10.894 μs   GC (min … max):  0.00% … 98.28%
 Time  (median):      84.122 ns                GC (median):     0.00%
 Time  (mean ± σ):   116.372 ns ± 241.468 ns   GC (mean ± σ):  16.26% ± 12.52%

  ▄▁            ▂▃▁                                            ▁
  ██▅▃▃▁▁▁▁▃▃▃▃███▆▄▃▃▁▁▁▄▁▁▁▁▁▁▁▁▁▁▁▁▄▄▄▄▄▄▄▄▄▄▄▅▄▄▄▄▄▄▅▄▆▆▆ █
  80.2 ns       Histogram: log(frequency) by time        808 ns <

 Memory estimate: 528 bytes, allocs estimate: 3.

We can use in-place or mutating functions to improve performance. This is one of the first things to think about optimizing when looking for speedups.

using LinearAlgebra: mul!

buffer = copy(Ψ)
@benchmark mul!(buffer, Ps, Ψ)
BenchmarkTools.Trial: 10000 samples with 989 evaluations per sample.
 Range (minmax):  46.011 ns225.010 ns   GC (min … max): 0.00% … 0.00%
 Time  (median):     48.990 ns                GC (median):    0.00%
 Time  (mean ± σ):   49.498 ns ±   2.800 ns   GC (mean ± σ):  0.00% ± 0.00%

         ▂▁▁▃▄▆▇██▄▃▃▂▁▁  ▂                       ▁▂▂▂▁▁▁   ▃
  ▄▅▁▅▆▆▆██████████████████▅▅▆▃▃▁▁▁▁▁▃▁▁▁▁▁▄▁▃▁▄▅▇███████▇▇ █
  46 ns         Histogram: log(frequency) by time      57.5 ns <

 Memory estimate: 0 bytes, allocs estimate: 0.

Composite spaces

We can create composite spaces and operators with the '\otimes' symbol representing the tensor product.

psi = fockstate(F,4)⊗spinup(S)
Ket(dim=52)
  basis: [Fock(cutoff=25) ⊗ Spin(1/2)]
 0.0 + 0.0im
 0.0 + 0.0im
 0.0 + 0.0im
 0.0 + 0.0im
 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
create(F)⊗identityoperator(S)
Operator(dim=52x52)
  basis: [Fock(cutoff=25) ⊗ Spin(1/2)]
⎡⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎤
⎢⠀⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠂⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠀⎥
⎣⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⡀⎦

This does not scale well! We have a function called embed to address this problem

embed(F⊗S, 1, create(F))
Operator(dim=52x52)
  basis: [Fock(cutoff=25) ⊗ Spin(1/2)]
⎡⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎤
⎢⠀⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠂⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠀⎥
⎣⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⡀⎦

We can take a partial trace with ptrace()

l = spindown(S)
h = spinup(S)

bell = (l⊗l + h⊗h) / √2

ptrace(bell,2)
Operator(dim=2x2)
  basis: Spin(1/2)
 0.5+0.0im  0.0+0.0im
 0.0+0.0im  0.5+0.0im

Coherent states

using QuantumOptics

QuantumOptics depends on DifferentialEquations, so has a much longer precompile time compared to QuantumOpticsBase, which defines the methods for working with quantum states and operators without any time evolution.

We will work with the quantum harmonic oscillator and look at coherent states in phase space.

cutoff = 32
B = FockBasis(cutoff)
ω = 1.0
a = destroy(B)

H = ω*a'*a
Operator(dim=33x33)
  basis: Fock(cutoff=32)
⎡⠐⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎤
⎢⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⎥
⎣⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⎦

Now we can make a coherent state

α = 4
ψ = coherentstate(B, α)
Ket(dim=33)
  basis: Fock(cutoff=32)
 0.00033546262790251 + 0.0im
 0.00134185051161005 + 0.0im
 0.00379532638439241 + 0.0im
 0.00876493083876579 + 0.0im
 0.01752986167753158 + 0.0im
 0.03135836987770328 + 0.0im
 0.05120800357722345 + 0.0im
 0.07741922434367954 + 0.0im
 0.10948731705523689 + 0.0im
 0.14598308940698249 + 0.0im
                     ⋮
  0.1198756849197267 + 0.0im
 0.09590054793578136 + 0.0im
 0.07523057927519837 + 0.0im
 0.05791252692776968 + 0.0im
 0.04377775544177429 + 0.0im
  0.0325173004055702 + 0.0im
 0.02374727858840358 + 0.0im
 0.01706054857273676 + 0.0im
 0.01206362958654464 + 0.0im
a*ψ ≈ α*ψ
false

TODO: what is going wrong here?

using CairoMakie
quad = -10:0.1:10

w = wigner(ψ,quad,quad)

fig = Figure()
ax = Axis(fig[1,1], aspect = DataAspect())
heatmap!(quad,quad,w)
fig
Example block output

Schrodinger dynamics

ts = 0:0.1:3*2*π

_, ψs = timeevolution.schroedinger(ts,ψ,H)
x = (a' + a)/√2
p = 1im*(a' - a)/√2

fig = Figure()
ax = Axis(fig[1,1], aspect = DataAspect())
lines!(ax,ts,real.(expect.((x,),ψs)))
lines!(ax,ts,real.(expect.((p,),ψs)))
fig
Example block output
lines(norm.(ψs))
Example block output

First, the naive way to create a time-dependent Hamiltonian

function Hdynamic(t,psi)
    return H+p*4*sin(8*ω*t)
end

_, ψs = timeevolution.schroedinger_dynamic(ts,ψ,Hdynamic)

fig = Figure()
ax = Axis(fig[1,1], aspect = DataAspect())
lines!(ax,ts,real.(expect.((x,),ψs)))
lines!(ax,ts,real.(expect.((p,),ψs)))
fig
Example block output

SciMLOperators has an interesting way to create time-dependent operators in an allocation-efficient way.

using BenchmarkTools
Hlazy = H + TimeDependentSum(t-> 4*sin(8*ω*t),p)
@benchmark _, ψs = timeevolution.schroedinger_dynamic(ts, ψ, Hlazy)
BenchmarkTools.Trial: 238 samples with 1 evaluation per sample.
 Range (minmax):  18.902 ms50.949 ms   GC (min … max): 0.00% … 59.58%
 Time  (median):     20.622 ms               GC (median):    0.00%
 Time  (mean ± σ):   21.007 ms ±  2.957 ms   GC (mean ± σ):  1.79% ±  6.44%

  ▄█  ▅   ▄▂                                                  
  ██▄█████▄▂▃▆▃▁▃▁▁▁▁▁▁▁▁▁▁▁▃▁▁▁▁▁▁▁▁▁▁▁▁▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▂ ▃
  18.9 ms         Histogram: frequency by time        35.5 ms <

 Memory estimate: 3.94 MiB, allocs estimate: 161486.

And the old way:

@benchmark _, ψs = timeevolution.schroedinger_dynamic(ts,ψ,Hdynamic)
BenchmarkTools.Trial: 112 samples with 1 evaluation per sample.
 Range (minmax):  38.850 ms110.757 ms   GC (min … max): 10.62% … 24.80%
 Time  (median):     40.539 ms                GC (median):    11.34%
 Time  (mean ± σ):   44.687 ms ±  13.574 ms   GC (mean ± σ):  13.26% ±  4.40%

  ██                                                        
  ███▁▁▁▁▅▁▁▁▁▅▁▁▁▁▁▁▁▁▁▁▁▁▅▁▁▁▁▁▁▁▁▁▅▁▁▁▅▁▁▁▅▁▅▅▁▅▁▁▅▁▁▁▁▁▅ ▅
  38.8 ms       Histogram: log(frequency) by time      97.1 ms <

 Memory estimate: 121.67 MiB, allocs estimate: 439236.

Trying out different solvers

using OrdinaryDiffEqLowOrderRK: DP5
using OrdinaryDiffEqTsit5: Tsit5
using OrdinaryDiffEqVerner: Vern8

A good discussion on Schrodinger dynamics and solver tolerance

@benchmark _, ψs = timeevolution.schroedinger_dynamic(ts, ψ, Hlazy; alg =
DP5())
BenchmarkTools.Trial: 235 samples with 1 evaluation per sample.
 Range (minmax):  19.082 ms57.405 ms   GC (min … max): 0.00% … 60.90%
 Time  (median):     20.746 ms               GC (median):    0.00%
 Time  (mean ± σ):   21.320 ms ±  3.562 ms   GC (mean ± σ):  1.95% ±  6.85%

  ▃  ▁█   ▁                                                    
  █▃▄███▃▄▆▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▂ ▃
  19.1 ms         Histogram: frequency by time        39.3 ms <

 Memory estimate: 3.94 MiB, allocs estimate: 161486.
@benchmark _, ψs = timeevolution.schroedinger_dynamic(ts, ψ, Hlazy; alg =
Tsit5())
BenchmarkTools.Trial: 231 samples with 1 evaluation per sample.
 Range (minmax):  19.965 ms51.499 ms   GC (min … max): 0.00% … 60.96%
 Time  (median):     21.663 ms               GC (median):    0.00%
 Time  (mean ± σ):   21.695 ms ±  3.451 ms   GC (mean ± σ):  2.02% ±  7.08%

  █▆   ▁                                                     
  ██▇▆▇██▄▄█▄▁▁▁▁▁▁▁▁▄▁▁▁▁▁▁▁▁▄▄▁▁▁▁▁▁▁▁▁▁▁▁▄▄▁▁▁▁▁▁▁▁▁▁▁▁▄ ▆
  20 ms        Histogram: log(frequency) by time      38.4 ms <

 Memory estimate: 4.19 MiB, allocs estimate: 172048.
@benchmark _, ψs = timeevolution.schroedinger_dynamic(ts, ψ, Hlazy; alg =
Vern8())
BenchmarkTools.Trial: 298 samples with 1 evaluation per sample.
 Range (minmax):  15.437 ms47.735 ms   GC (min … max): 0.00% … 64.67%
 Time  (median):     16.004 ms               GC (median):    0.00%
 Time  (mean ± σ):   16.820 ms ±  2.967 ms   GC (mean ± σ):  2.33% ±  7.20%

  █▇▂ ▁ ▅▇▅                                                   
  ███▄█████▄▄▄▄▁▁▄▄▄▁▁▁▄▁▁▁▁▁▁▁▄▁▁▁▁▁▁▁▁▁▁▁▁▄▁▁▁▁▁▁▁▁▁▁▁▁▁▄ ▆
  15.4 ms      Histogram: log(frequency) by time      29.2 ms <

 Memory estimate: 4.12 MiB, allocs estimate: 130192.

Master equation evolution

γ = 0.1
_, ρs = timeevolution.master(ts,ψ,H,[√γ*a])

fig = Figure()
ax = Axis(fig[1,1], aspect = DataAspect())
lines!(ax,ts,real.(expect.((x,),ρs)))
lines!(ax,ts,real.(expect.((p,),ρs)))
fig
Example block output

TODO: Lindblad is nonlinear with respect to collapse operators?