Skip to content

Commit 6bc3b9b

Browse files
TendonFFFcailixun
andauthored
First try of ENR implementation (#499)
Co-authored-by: cailixun <[email protected]>
1 parent 3028fe0 commit 6bc3b9b

File tree

5 files changed

+167
-13
lines changed

5 files changed

+167
-13
lines changed

src/QuantumToolbox.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ include("linear_maps.jl")
8484

8585
# Quantum Object
8686
include("qobj/space.jl")
87+
include("qobj/energy_restricted.jl")
8788
include("qobj/dimensions.jl")
8889
include("qobj/quantum_object_base.jl")
8990
include("qobj/quantum_object.jl")

src/qobj/dimensions.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,8 @@ function _get_dims_string(dimensions::GeneralDimensions)
9898
return "[$(string(dims[1])), $(string(dims[2]))]"
9999
end
100100
_get_dims_string(::Nothing) = "nothing" # for EigsolveResult.dimensions = nothing
101+
102+
Base.:(==)(dim1::Dimensions, dim2::Dimensions) = (dim1.to == dim2.to)
103+
Base.:(==)(dim1::GeneralDimensions, dim2::GeneralDimensions) = (dim1.to == dim2.to) && (dim1.from == dim2.from)
104+
Base.:(==)(dim1::Dimensions, dim2::GeneralDimensions) = false
105+
Base.:(==)(dim1::GeneralDimensions, dim2::Dimensions) = false

src/qobj/energy_restricted.jl

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
#=
2+
This file defines the energy restricted space structure.
3+
=#
4+
5+
export EnrSpace, enr_state_dictionaries
6+
export enr_identity, enr_fock, enr_destroy, enr_thermal_dm
7+
8+
struct EnrSpace{N} <: AbstractSpace
9+
size::Int
10+
dims::NTuple{N,Int}
11+
n_excitations::Int
12+
state2idx::Dict{SVector{N,Int},Int}
13+
idx2state::Dict{Int,SVector{N,Int}}
14+
15+
function EnrSpace(dims::Union{Tuple,AbstractVector}, excitations::Int)
16+
_non_static_array_warning("dims", dims)
17+
dim_len = length(dims)
18+
dims_T = NTuple{dim_len}(dims)
19+
20+
size, state2idx, idx2state = enr_state_dictionaries(dims, excitations)
21+
22+
return new{dim_len}(size, dims_T, excitations, state2idx, idx2state)
23+
end
24+
end
25+
26+
function Base.show(io::IO, s::EnrSpace)
27+
print(io, "EnrSpace($(s.dims), $(s.n_excitations))")
28+
return nothing
29+
end
30+
31+
Base.:(==)(s_enr1::EnrSpace, s_enr2::EnrSpace) = (all([s_enr1.size, s_enr1.dims] .== [s_enr2.size, s_enr2.dims]))
32+
33+
dimensions_to_dims(s_enr::EnrSpace) = s_enr.dims
34+
35+
function enr_state_dictionaries(dims::Union{Tuple,AbstractVector}, excitations::Int)
36+
len = length(dims)
37+
nvec = zeros(Int, len)
38+
result = SVector{len,Int}[nvec] # in the following, all nvec will first be converted (copied) to SVector and then push to result
39+
nexc = 0
40+
41+
while true
42+
idx = len
43+
nvec[end] += 1
44+
nexc += 1
45+
if nvec[idx] < dims[idx]
46+
push!(result, nvec)
47+
end
48+
while (nexc == excitations) || (nvec[idx] == dims[idx])
49+
#nvec[idx] = 0
50+
idx -= 1
51+
if idx < 1
52+
enr_size = length(result)
53+
return (enr_size, Dict(zip(result, 1:enr_size)), Dict(zip(1:enr_size, result)))
54+
end
55+
56+
nexc -= nvec[idx+1] - 1
57+
nvec[idx+1] = 0
58+
nvec[idx] += 1
59+
if nvec[idx] < dims[idx]
60+
push!(result, nvec)
61+
end
62+
end
63+
end
64+
end
65+
66+
function enr_identity(dims::Union{Tuple,AbstractVector}, excitations::Int)
67+
s_enr = EnrSpace(dims, excitations)
68+
return QuantumObject(Diagonal(ones(ComplexF64, s_enr.size)), Operator(), Dimensions(s_enr))
69+
end
70+
71+
function enr_fock(
72+
dims::Union{Tuple,AbstractVector},
73+
excitations::Int,
74+
state::AbstractVector;
75+
sparse::Union{Bool,Val} = Val(false),
76+
)
77+
s_enr = EnrSpace(dims, excitations)
78+
if getVal(sparse)
79+
array = sparsevec([s_enr.state2idx[[state...]]], [1.0 + 0im], s_enr.size)
80+
else
81+
j = s_enr.state2idx[state]
82+
array = [i == j ? 1.0 + 0im : 0.0 + 0im for i in 1:(s_enr.size)]
83+
84+
# s = zeros(ComplexF64, s_enr.size)
85+
# s[s_enr.state2idx[state]] += 1
86+
# s
87+
end
88+
89+
return QuantumObject(array, Ket(), s_enr)
90+
end
91+
92+
function enr_destroy(dims::Union{Tuple,AbstractVector}, excitations::Int)
93+
s_enr = EnrSpace(dims, excitations)
94+
N = s_enr.size
95+
idx2state = s_enr.idx2state
96+
state2idx = s_enr.state2idx
97+
98+
a_ops = ntuple(i -> QuantumObject(spzeros(ComplexF64, N, N), Operator(), s_enr), length(dims))
99+
100+
for (n1, state1) in idx2state
101+
for (idx, s) in pairs(state1)
102+
# if s > 0, the annihilation operator of mode idx has a non-zero
103+
# entry with one less excitation in mode idx in the final state
104+
if s > 0
105+
state2 = Vector(state1)
106+
state2[idx] -= 1
107+
n2 = state2idx[state2]
108+
a_ops[idx][n2, n1] = s
109+
end
110+
end
111+
end
112+
113+
return a_ops
114+
end
115+
116+
function enr_thermal_dm(dims::Union{Tuple,AbstractVector}, excitations::Int, n::Union{Int,AbstractVector})
117+
if n isa Number
118+
nvec = Vector{typeof(n)}(n, length(dims))
119+
else
120+
length(n) == length(dims) || throw(ArgumentError("The Vector `n` has different length to `dims`."))
121+
nvec = n
122+
end
123+
124+
s_enr = EnrSpace(dims, excitations)
125+
N = s_enr.size
126+
idx2state = s_enr.idx2state
127+
128+
diags = [prod((nvec ./ (1 .+ nvec)) .^ idx2state[idx]) for idx in 1:N]
129+
130+
diags /= sum(diags)
131+
132+
return QuantumObject(Diagonal(diags), Operator(), s_enr)
133+
end

src/qobj/space.jl

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,3 @@ dimensions_to_dims(s::Space) = SVector{1,Int}(s.size)
2626

2727
# this creates a list of Space(1), it is used to generate `from` for Ket, and `to` for Bra)
2828
space_one_list(N::Int) = ntuple(i -> Space(1), Val(N))
29-
30-
# TODO: introduce energy restricted space
31-
#=
32-
struct EnrSpace{N} <: AbstractSpace
33-
size::Int
34-
dims::SVector{N,Int}
35-
n_excitations::Int
36-
state2idx
37-
idx2state
38-
end
39-
40-
dimensions_to_dims(s::EnrSpace) = s.dims
41-
=#
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
@testitem "Excitation number restricted state space" begin
2+
@testset "mesolve" begin
3+
ε = 2π
4+
ωc = 2π
5+
g = 0.1ωc
6+
γ = 0.01ωc
7+
tlist = range(0, 20, 100)
8+
N_cut = 2
9+
10+
sz = sigmaz() qeye(N_cut)
11+
sm = sigmam() qeye(N_cut)
12+
a = qeye(2) destroy(N_cut)
13+
14+
H_JC = 0.5ε * sz + ωc * a' * a + g * (sm' * a + a' * sm)
15+
ψ0 = basis(2, 0) fock(N_cut, 0)
16+
sol_JC = mesolve(H_JC, ψ0, tlist, [γ * a]; e_ops = [sz], progress_bar = Val(false))
17+
18+
N_exc = 1
19+
dims = [2, N_cut]
20+
sm_enr, a_enr = enr_destroy(dims, N_exc)
21+
sz_enr = 2 * sm_enr' * sm_enr - 1
22+
ψ0_enr = enr_fock(dims, N_exc, [1, 0])
23+
H_enr = ε * sm_enr' * sm_enr + ωc * a_enr' * a_enr + g * (sm_enr' * a_enr + a_enr' * sm_enr)
24+
sol_enr = mesolve(H_enr, ψ0_enr, tlist, [γ * a_enr]; e_ops = [sz_enr], progress_bar = Val(false))
25+
26+
@test all(isapprox.(sol_JC.expect, sol_enr.expect, atol = 1e-4))
27+
end
28+
end

0 commit comments

Comments
 (0)