Skip to content

Commit 3e65459

Browse files
author
cailixun
committed
fix bug and add test
1 parent e1fbab2 commit 3e65459

File tree

5 files changed

+80
-50
lines changed

5 files changed

+80
-50
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 & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ dimensions_to_dims(dimensions::GeneralDimensions) =
7878
SVector{2}(dimensions_to_dims(dimensions.to), dimensions_to_dims(dimensions.from))
7979

8080
dimensions_to_dims(::Nothing) = nothing # for EigsolveResult.dimensions = nothing
81-
dimensions_to_dims(s_enr::EnrSpace) = s_enr.dims
8281

8382
Base.length(::AbstractDimensions{N}) where {N} = N
8483

@@ -99,3 +98,8 @@ function _get_dims_string(dimensions::GeneralDimensions)
9998
return "[$(string(dims[1])), $(string(dims[2]))]"
10099
end
101100
_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: 46 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,86 @@
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+
18
struct EnrSpace{N} <: AbstractSpace
29
size::Int
3-
dims::SVector{N,Int}
10+
dims::NTuple{N,Int}
411
n_excitations::Int
5-
state2idx::Dict{}
6-
idx2state::Dict{}
12+
state2idx::Dict{SVector{N,Int},Int}
13+
idx2state::Dict{Int,SVector{N,Int}}
714

8-
function EnrSpace(dims::Union{Tuple, AbstractVector}, excitations::Int)
15+
function EnrSpace(dims::Union{Tuple,AbstractVector}, excitations::Int)
916
_non_static_array_warning("dims", dims)
1017
dim_len = length(dims)
1118
dims_T = NTuple{dim_len}(dims)
1219

1320
size, state2idx, idx2state = enr_state_dictionaries(dims, excitations)
14-
1521

1622
return new{dim_len}(size, dims_T, excitations, state2idx, idx2state)
1723
end
1824
end
1925

20-
function enr_state_dictionaries(dims::Union{Tuple, AbstractVector}, excitations::Int)
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)
2136
len = length(dims)
22-
nvec = MVector{len}(zeros(Int, len))
23-
result = [copy(nvec)]
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
2439
nexc = 0
2540

2641
while true
2742
idx = len
2843
nvec[end] += 1
2944
nexc += 1
3045
if nvec[idx] < dims[idx]
31-
push!(result, copy(nvec))
46+
push!(result, nvec)
3247
end
3348
while (nexc == excitations) || (nvec[idx] == dims[idx])
3449
#nvec[idx] = 0
3550
idx -= 1
3651
if idx < 1
3752
enr_size = length(result)
38-
return (
39-
enr_size,
40-
Dict(zip(result, 1:enr_size)),
41-
Dict(zip(1:enr_size, result))
42-
)
53+
return (enr_size, Dict(zip(result, 1:enr_size)), Dict(zip(1:enr_size, result)))
4354
end
4455

4556
nexc -= nvec[idx+1] - 1
4657
nvec[idx+1] = 0
4758
nvec[idx] += 1
4859
if nvec[idx] < dims[idx]
49-
push!(result, copy(nvec))
60+
push!(result, nvec)
5061
end
5162
end
5263
end
53-
5464
end
5565

56-
function enr_identity(dims::Union{Tuple, AbstractVector}, excitations::Int)
66+
function enr_identity(dims::Union{Tuple,AbstractVector}, excitations::Int)
5767
s_enr = EnrSpace(dims, excitations)
5868
return QuantumObject(Diagonal(ones(ComplexF64, s_enr.size)), Operator(), Dimensions(s_enr))
5969
end
6070

6171
function enr_fock(
62-
dims::Union{Tuple, AbstractVector}, excitations::Int, state::AbstractVector;
63-
sparse::Union{Bool,Val} = Val(false)
64-
)
72+
dims::Union{Tuple,AbstractVector},
73+
excitations::Int,
74+
state::AbstractVector;
75+
sparse::Union{Bool,Val} = Val(false),
76+
)
6577
s_enr = EnrSpace(dims, excitations)
6678
if getVal(sparse)
6779
array = sparsevec([s_enr.state2idx[[state...]]], [1.0 + 0im], s_enr.size)
6880
else
6981
j = s_enr.state2idx[state]
7082
array = [i == j ? 1.0 + 0im : 0.0 + 0im for i in 1:(s_enr.size)]
71-
83+
7284
# s = zeros(ComplexF64, s_enr.size)
7385
# s[s_enr.state2idx[state]] += 1
7486
# s
@@ -77,40 +89,38 @@ function enr_fock(
7789
return QuantumObject(array, Ket(), s_enr)
7890
end
7991

80-
function enr_destroy(dims::Union{Tuple, AbstractVector}, excitations::Int)
92+
function enr_destroy(dims::Union{Tuple,AbstractVector}, excitations::Int)
8193
s_enr = EnrSpace(dims, excitations)
8294
N = s_enr.size
8395
idx2state = s_enr.idx2state
8496
state2idx = s_enr.state2idx
8597

86-
a_ops = [zeros(ComplexF64, N, N) for _ in 1:length(dims)]
98+
a_ops = ntuple(i -> QuantumObject(spzeros(ComplexF64, N, N), Operator(), s_enr), length(dims))
8799

88100
for (n1, state1) in idx2state
89101
for (idx, s) in pairs(state1)
90-
s > 0 || continue
91-
92-
state2 = copy(state1)
93-
state2[idx] -= 1
94-
n2 = state2idx[state2]
95-
a_ops[idx][n2, n1] += s
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
96110
end
97111
end
98112

99-
return [QuantumObject(array, Operator(), s_enr) for array in a_ops]
113+
return a_ops
100114
end
101115

102-
function enr_thermal_dm(
103-
dims::Union{Tuple, AbstractVector},
104-
excitations::Int,
105-
n::Union{Int, AbstractVector}
106-
)
116+
function enr_thermal_dm(dims::Union{Tuple,AbstractVector}, excitations::Int, n::Union{Int,AbstractVector})
107117
if n isa Number
108118
nvec = Vector{typeof(n)}(n, length(dims))
109119
else
110120
length(n) == length(dims) || throw(ArgumentError("The Vector `n` has different length to `dims`."))
111121
nvec = n
112122
end
113-
123+
114124
s_enr = EnrSpace(dims, excitations)
115125
N = s_enr.size
116126
idx2state = s_enr.idx2state

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-
=#

test/core-test/enr_state_operator.jl

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)