Skip to content

Commit a2dfff1

Browse files
committed
fix tensor and GeneralDimensions for EnrSpace
1 parent c6fdeb0 commit a2dfff1

File tree

5 files changed

+85
-18
lines changed

5 files changed

+85
-18
lines changed

src/qobj/dimensions.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ Dimensions(dims::Any) = throw(
4343
A structure that describes the left-hand side (`to`) and right-hand side (`from`) Hilbert [`Space`](@ref) of an [`Operator`](@ref).
4444
"""
4545
struct GeneralDimensions{M,N,T1<:Tuple,T2<:Tuple} <: AbstractDimensions{M,N}
46-
# note that the number `N` should be the same for both `to` and `from`
4746
to::T1 # space acting on the left
4847
from::T2 # space acting on the right
4948

src/qobj/energy_restricted.jl

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,17 @@ export enr_identity, enr_fock, enr_destroy, enr_thermal_dm
1010
size::Int
1111
dims::NTuple{N,Int}
1212
n_excitations::Int
13-
n_subspace::Int
1413
state2idx::Dict{SVector{N,Int},Int}
1514
idx2state::Dict{Int,SVector{N,Int}}
1615
end
1716
18-
A structure that describes an excitation-number restricted (ENR) state space.
17+
A structure that describes an excitation-number restricted (ENR) state space, where `N` is the number of sub-systems.
1918
2019
# Fields
2120
2221
- `size`: Number of states in the excitation-number restricted state space
2322
- `dims`: A list of the number of states in each sub-system
2423
- `n_excitations`: Maximum number of excitations
25-
- `n_subspace`: The number of sub-systems
2624
- `state2idx`: A dictionary for looking up a state index from a state (`SVector`)
2725
- `idx2state`: A dictionary for looking up state (`SVector`) from a state index
2826
@@ -43,7 +41,6 @@ struct EnrSpace{N} <: AbstractSpace
4341
size::Int
4442
dims::SVector{N,Int}
4543
n_excitations::Int
46-
n_subspace::Int
4744
state2idx::Dict{SVector{N,Int},Int}
4845
idx2state::Dict{Int,SVector{N,Int}}
4946

@@ -52,7 +49,7 @@ struct EnrSpace{N} <: AbstractSpace
5249
size, state2idx, idx2state = enr_state_dictionaries(dims, excitations)
5350

5451
L = length(dims)
55-
return new{L}(size, SVector{L}(dims), excitations, L, state2idx, idx2state)
52+
return new{L}(size, SVector{L}(dims), excitations, state2idx, idx2state)
5653
end
5754
end
5855

@@ -116,8 +113,9 @@ end
116113

117114
function enr_identity(dims::Union{AbstractVector{T},NTuple{N,T}}, excitations::Int) where {T<:Integer,N}
118115
s_enr = EnrSpace(dims, excitations)
119-
return QuantumObject(Diagonal(ones(ComplexF64, s_enr.size)), Operator(), Dimensions(s_enr))
116+
return enr_identity(s_enr)
120117
end
118+
enr_identity(s_enr::EnrSpace) = QuantumObject(Diagonal(ones(ComplexF64, s_enr.size)), Operator(), Dimensions(s_enr))
121119

122120
function enr_fock(
123121
dims::Union{AbstractVector{T},NTuple{N,T}},
@@ -126,6 +124,13 @@ function enr_fock(
126124
sparse::Union{Bool,Val} = Val(false),
127125
) where {T<:Integer,N}
128126
s_enr = EnrSpace(dims, excitations)
127+
return enr_fock(s_enr, state, sparse = sparse)
128+
end
129+
function enr_fock(
130+
s_enr::EnrSpace,
131+
state::AbstractVector{T};
132+
sparse::Union{Bool,Val} = Val(false),
133+
) where {T<:Integer}
129134
if getVal(sparse)
130135
array = sparsevec([s_enr.state2idx[[state...]]], [1.0 + 0im], s_enr.size)
131136
else
@@ -136,13 +141,19 @@ function enr_fock(
136141
return QuantumObject(array, Ket(), s_enr)
137142
end
138143

139-
function enr_destroy(dims::Union{AbstractVector{T},NTuple{N,T}}, excitations::Int) where {T<:Integer,N}
144+
function enr_destroy(
145+
dims::Union{AbstractVector{T},NTuple{N,T}},
146+
excitations::Int
147+
) where {T<:Integer,N}
140148
s_enr = EnrSpace(dims, excitations)
149+
return enr_destroy(s_enr)
150+
end
151+
function enr_destroy(s_enr::EnrSpace{N}) where {N}
141152
D = s_enr.size
142153
idx2state = s_enr.idx2state
143154
state2idx = s_enr.state2idx
144155

145-
a_ops = ntuple(i -> QuantumObject(spzeros(ComplexF64, D, D), Operator(), s_enr), s_enr.n_subspace)
156+
a_ops = ntuple(i -> QuantumObject(spzeros(ComplexF64, D, D), Operator(), s_enr), N)
146157

147158
for (n1, state1) in idx2state
148159
for (idx, s) in pairs(state1)
@@ -162,11 +173,13 @@ end
162173

163174
function enr_thermal_dm(dims::Union{AbstractVector{T1},NTuple{N,T1}}, excitations::Int, n::Union{T2,AbstractVector{T2}}) where {T1<:Integer,T2<:Real,N}
164175
s_enr = EnrSpace(dims, excitations)
165-
176+
return enr_thermal_dm(s_enr, n)
177+
end
178+
function enr_thermal_dm(s_enr::EnrSpace{N}, n::Union{T,AbstractVector{T}}) where {N,T<:Real}
166179
if n isa Real
167-
nvec = fill(n, s_enr.n_subspace)
180+
nvec = fill(n, N)
168181
else
169-
(length(n) == s_enr.n_subspace) || throw(ArgumentError("The length of the vector `n` should be the same as `dims`."))
182+
(length(n) == N) || throw(ArgumentError("The length of the vector `n` should be the same as `dims`."))
170183
nvec = n
171184
end
172185

src/qobj/quantum_object_base.jl

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,22 +222,27 @@ end
222222

223223
# this returns `to` in GeneralDimensions representation
224224
get_dimensions_to(A::AbstractQuantumObject{Ket,<:Dimensions}) = A.dimensions.to
225-
get_dimensions_to(A::AbstractQuantumObject{Bra,<:Dimensions{N}}) where {N} = space_one_list(N)
225+
get_dimensions_to(A::AbstractQuantumObject{Bra,<:Dimensions}) = space_one_list(A.dimensions.to)
226226
get_dimensions_to(A::AbstractQuantumObject{Operator,<:Dimensions}) = A.dimensions.to
227227
get_dimensions_to(A::AbstractQuantumObject{Operator,<:GeneralDimensions}) = A.dimensions.to
228228
get_dimensions_to(
229229
A::AbstractQuantumObject{ObjType,<:Dimensions},
230230
) where {ObjType<:Union{SuperOperator,OperatorBra,OperatorKet}} = A.dimensions.to
231231

232232
# this returns `from` in GeneralDimensions representation
233-
get_dimensions_from(A::AbstractQuantumObject{Ket,<:Dimensions{N}}) where {N} = space_one_list(N)
233+
get_dimensions_from(A::AbstractQuantumObject{Ket,<:Dimensions}) = space_one_list(A.dimensions.to)
234234
get_dimensions_from(A::AbstractQuantumObject{Bra,<:Dimensions}) = A.dimensions.to
235235
get_dimensions_from(A::AbstractQuantumObject{Operator,<:Dimensions}) = A.dimensions.to
236236
get_dimensions_from(A::AbstractQuantumObject{Operator,<:GeneralDimensions}) = A.dimensions.from
237237
get_dimensions_from(
238238
A::AbstractQuantumObject{ObjType,<:Dimensions},
239239
) where {ObjType<:Union{SuperOperator,OperatorBra,OperatorKet}} = A.dimensions.to
240240

241+
# this creates a list of Space(1), it is used to generate `from` for Ket, and `to` for Bra
242+
space_one_list(dimensions::NTuple{N,AbstractSpace}) where {N} = ntuple(i -> Space(1), Val(sum(_get_dims_length, dimensions)))
243+
_get_dims_length(::Space) = 1
244+
_get_dims_length(::EnrSpace{N}) where {N} = N
245+
241246
# functions for getting Float or Complex element type
242247
_FType(A::AbstractQuantumObject) = _FType(eltype(A))
243248
_CType(A::AbstractQuantumObject) = _CType(eltype(A))

src/qobj/space.jl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,3 @@ struct Space <: AbstractSpace
2323
end
2424

2525
dimensions_to_dims(s::Space) = SVector{1,Int}(s.size)
26-
27-
# this creates a list of Space(1), it is used to generate `from` for Ket, and `to` for Bra)
28-
space_one_list(N::Int) = ntuple(i -> Space(1), Val(N))

test/core-test/enr_state_operator.jl

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,49 @@
11
@testitem "Excitation number restricted state space" begin
2+
@testset "kron" begin
3+
# normal Space
4+
D1 = 4
5+
D2 = 5
6+
dims_s = (D1, D2)
7+
ρ_s = rand_dm(dims_s)
8+
I_s = qeye(D1) qeye(D2)
9+
size_s = prod(dims_s)
10+
space_s = (Space(D1), Space(D2))
11+
12+
# EnrSpace
13+
dims_enr = (2, 2, 3)
14+
excitations = 3
15+
space_enr = EnrSpace(dims_enr, excitations)
16+
ρ_enr = enr_thermal_dm(space_enr, rand(3))
17+
I_enr = enr_identity(space_enr)
18+
size_enr = space_enr.size
19+
20+
# tensor between normal and ENR space
21+
ρ_tot = tensor(ρ_s, ρ_enr)
22+
opstring = sprint((t, s) -> show(t, "text/plain", s), ρ_tot)
23+
datastring = sprint((t, s) -> show(t, "text/plain", s), ρ_tot.data)
24+
ρ_tot_dims = [dims_s..., dims_enr...]
25+
ρ_tot_size = size_s * size_enr
26+
ρ_tot_isherm = isherm(ρ_tot)
27+
@test opstring ==
28+
"\nQuantum Object: type=Operator() dims=$ρ_tot_dims size=$((ρ_tot_size, ρ_tot_size)) ishermitian=$ρ_tot_isherm\n$datastring"
29+
30+
# use GeneralDimensions to do partial trace
31+
new_dims1 = GeneralDimensions((Space(1), Space(1), space_enr), (Space(1), Space(1), space_enr))
32+
ρ_enr_compound = Qobj(zeros(ComplexF64, size_enr, size_enr), dims = new_dims1)
33+
basis_list = [tensor(basis(D1, i), basis(D2, j)) for i in 0:(D1-1) for j in 0:(D2-1)]
34+
for b in basis_list
35+
ρ_enr_compound += tensor(b', I_enr) * ρ_tot * tensor(b, I_enr)
36+
end
37+
new_dims2 = GeneralDimensions((space_s..., Space(1), Space(1), Space(1)), (space_s..., Space(1), Space(1), Space(1)))
38+
ρ_s_compound = Qobj(zeros(ComplexF64, size_s, size_s), dims = new_dims2)
39+
basis_list = [enr_fock(space_enr, space_enr.idx2state[idx]) for idx in 1:space_enr.size]
40+
for b in basis_list
41+
ρ_s_compound += tensor(I_s, b') * ρ_tot * tensor(I_s, b)
42+
end
43+
@test ρ_enr.data ρ_enr_compound.data
44+
@test ρ_s.data ρ_s_compound.data
45+
end
46+
247
@testset "mesolve, steadystate, and eigenstates" begin
348
ε = 2π
449
ωc = 2π
@@ -37,7 +82,15 @@
3782
# check eigenstates
3883
λ, v = eigenstates(H_enr)
3984
@test all([H_enr * v[k] λ[k] * v[k] for k in eachindex(λ)])
85+
end
4086

41-
qeye(3) H_enr
87+
@testset "Type Inference" begin
88+
N = 3
89+
dims = (2, 2, 3)
90+
excitations = 3
91+
@inferred enr_identity(dims, excitations)
92+
@inferred enr_fock(dims, excitations, zeros(Int, N))
93+
@inferred enr_destroy(dims, excitations)
94+
@inferred enr_thermal_dm(dims, excitations, rand(N))
4295
end
4396
end

0 commit comments

Comments
 (0)