Skip to content

Commit 1cccacf

Browse files
ytdHuangalbertomercurio
authored andcommitted
support time-dependent lindblad_dissipator
1 parent 5654933 commit 1cccacf

File tree

2 files changed

+77
-23
lines changed

2 files changed

+77
-23
lines changed

src/qobj/superoperators.jl

Lines changed: 61 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Functions for generating (common) quantum super-operators.
55
export spre, spost, sprepost, liouvillian, lindblad_dissipator
66

77
# intrinsic functions for super-operators
8-
# (keep these because they take AbstractMatrix as input and ensure the output is sparse matrix)
8+
## keep these because they take AbstractMatrix as input and ensure the output is sparse matrix
99
_spre(A::AbstractMatrix, Id::AbstractMatrix) = kron(Id, sparse(A))
1010
_spre(A::AbstractSparseMatrix, Id::AbstractMatrix) = kron(Id, A)
1111
_spost(B::AbstractMatrix, Id::AbstractMatrix) = kron(transpose(sparse(B)), Id)
@@ -14,19 +14,53 @@ _sprepost(A::AbstractMatrix, B::AbstractMatrix) = kron(transpose(sparse(B)), spa
1414
_sprepost(A::AbstractMatrix, B::AbstractSparseMatrix) = kron(transpose(B), sparse(A))
1515
_sprepost(A::AbstractSparseMatrix, B::AbstractMatrix) = kron(transpose(sparse(B)), A)
1616
_sprepost(A::AbstractSparseMatrix, B::AbstractSparseMatrix) = kron(transpose(B), A)
17+
function _sprepost(A, B) # for any other input types
18+
Id_cache = I(size(A, 1))
19+
return _spre(A, Id_cache) * _spost(B, Id_cache)
20+
end
21+
1722
_liouvillian(H::AbstractMatrix, Id::AbstractMatrix) = -1im * (_spre(H, Id) - _spost(H, Id))
23+
function _lindblad_dissipator(O::AbstractMatrix, Id::AbstractMatrix)
24+
Od_O = O' * O
25+
return _sprepost(O, O') - (_spre(Od_O, Id) + _spost(Od_O, Id)) / 2
26+
end
1827

19-
# (if input is AbstractSciMLOperator)
28+
## if input is AbstractSciMLOperator
29+
_lazy_tensor_warning(func_name::String, data::AbstractSciMLOperator) =
30+
@warn "The function `$func_name` uses lazy tensor (which can hurt performance) for data type: $(get_typename_wrapper(data))"
2031
_spre(A::MatrixOperator, Id::AbstractMatrix) = MatrixOperator(_spre(A.A, Id))
2132
_spre(A::ScaledOperator, Id::AbstractMatrix) = ScaledOperator(A.λ, _spre(A.L, Id))
2233
_spre(A::AddedOperator, Id::AbstractMatrix) = mapreduce(op -> _spre(op, Id), +, A.ops)
34+
function _spre(A::AbstractSciMLOperator, Id::AbstractMatrix)
35+
_lazy_tensor_warning("spre", A)
36+
return kron(Id, A)
37+
end
38+
2339
_spost(B::MatrixOperator, Id::AbstractMatrix) = MatrixOperator(_spost(B.A, Id))
2440
_spost(B::ScaledOperator, Id::AbstractMatrix) = ScaledOperator(B.λ, _spost(B.L, Id))
2541
_spost(B::AddedOperator, Id::AbstractMatrix) = mapreduce(op -> _spost(op, Id), +, B.ops)
42+
function _spost(B::AbstractSciMLOperator, Id::AbstractMatrix)
43+
_lazy_tensor_warning("spost", B)
44+
return kron(transpose(B), Id)
45+
end
46+
2647
_liouvillian(H::MatrixOperator, Id::AbstractMatrix) = MatrixOperator(_liouvillian(H.A, Id))
2748
_liouvillian(H::ScaledOperator, Id::AbstractMatrix) = ScaledOperator(H.λ, _liouvillian(H.L, Id))
2849
_liouvillian(H::AddedOperator, Id::AbstractMatrix) = mapreduce(op -> _liouvillian(op, Id), +, H.ops)
29-
# TODO: support `_sprepost`, `sprepost`, and `lindblad_dissipator` for AbstractSciMLOperator (allow c_ops with Vector{QobjEvo})
50+
_liouvillian(H::AbstractSciMLOperator, Id::AbstractMatrix) = -1im * (_spre(H, Id) - _spost(H, Id))
51+
function _lindblad_dissipator(O::MatrixOperator, Id::AbstractMatrix)
52+
_O = O.A
53+
Od_O = _O' * _O
54+
return MatrixOperator(_sprepost(_O, _O') - (_spre(Od_O, Id) + _spost(Od_O, Id)) / 2)
55+
end
56+
function _lindblad_dissipator(O::ScaledOperator, Id::AbstractMatrix)
57+
λc_λ = conj(O.λ) * O.λ
58+
return ScaledOperator(λc_λ, _lindblad_dissipator(O.L, Id))
59+
end
60+
function _lindblad_dissipator(O::AbstractSciMLOperator, Id::AbstractMatrix)
61+
Od_O = O' * O
62+
return _sprepost(O, O') - (_spre(Od_O, Id) + _spost(Od_O, Id)) / 2
63+
end
3064

3165
@doc raw"""
3266
spre(A::AbstractQuantumObject, Id_cache=I(size(A,1)))
@@ -41,6 +75,8 @@ Since the density matrix is vectorized in [`OperatorKet`](@ref) form: ``|\hat{\r
4175
(see the section in documentation: [Superoperators and Vectorized Operators](@ref doc:Superoperators-and-Vectorized-Operators) for more details)
4276
4377
The optional argument `Id_cache` can be used to pass a precomputed identity matrix. This can be useful when the same function is applied multiple times with a known Hilbert space dimension.
78+
79+
See also [`spost`](@ref) and [`sprepost`](@ref).
4480
"""
4581
spre(A::AbstractQuantumObject{DT,OperatorQuantumObject}, Id_cache = I(size(A, 1))) where {DT} =
4682
get_typename_wrapper(A)(_spre(A.data, Id_cache), SuperOperator, A.dims)
@@ -58,12 +94,14 @@ Since the density matrix is vectorized in [`OperatorKet`](@ref) form: ``|\hat{\r
5894
(see the section in documentation: [Superoperators and Vectorized Operators](@ref doc:Superoperators-and-Vectorized-Operators) for more details)
5995
6096
The optional argument `Id_cache` can be used to pass a precomputed identity matrix. This can be useful when the same function is applied multiple times with a known Hilbert space dimension.
97+
98+
See also [`spre`](@ref) and [`sprepost`](@ref).
6199
"""
62100
spost(B::AbstractQuantumObject{DT,OperatorQuantumObject}, Id_cache = I(size(B, 1))) where {DT} =
63101
get_typename_wrapper(B)(_spost(B.data, Id_cache), SuperOperator, B.dims)
64102

65103
@doc raw"""
66-
sprepost(A::QuantumObject, B::QuantumObject)
104+
sprepost(A::AbstractQuantumObject, B::AbstractQuantumObject)
67105
68106
Returns the [`SuperOperator`](@ref) form of `A` and `B` acting on the left and right of the density matrix operator, respectively: ``\mathcal{O} \left( \hat{A}, \hat{B} \right) \left[ \hat{\rho} \right] = \hat{A} \hat{\rho} \hat{B}``.
69107
@@ -77,16 +115,15 @@ Since the density matrix is vectorized in [`OperatorKet`](@ref) form: ``|\hat{\r
77115
See also [`spre`](@ref) and [`spost`](@ref).
78116
"""
79117
function sprepost(
80-
A::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject},
81-
B::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject},
82-
) where {T1,T2}
118+
A::AbstractQuantumObject{DT1,OperatorQuantumObject},
119+
B::AbstractQuantumObject{DT2,OperatorQuantumObject},
120+
) where {DT1,DT2}
83121
check_dims(A, B)
84-
85-
return QuantumObject(_sprepost(A.data, B.data), SuperOperator, A.dims)
122+
return promote_op_type(A, B)(_sprepost(A.data, B.data), SuperOperator, A.dims)
86123
end
87124

88125
@doc raw"""
89-
lindblad_dissipator(O::QuantumObject, Id_cache=I(size(O,1))
126+
lindblad_dissipator(O::AbstractQuantumObject, Id_cache=I(size(O,1))
90127
91128
Returns the Lindblad [`SuperOperator`](@ref) defined as
92129
@@ -99,14 +136,11 @@ The optional argument `Id_cache` can be used to pass a precomputed identity matr
99136
100137
See also [`spre`](@ref), [`spost`](@ref), and [`sprepost`](@ref).
101138
"""
102-
function lindblad_dissipator(O::QuantumObject{DT,OperatorQuantumObject}, Id_cache = I(size(O, 1))) where {DT}
103-
Od_O = O' * O
104-
return sprepost(O, O') - (spre(Od_O, Id_cache) + spost(Od_O, Id_cache)) / 2
105-
end
106-
# TODO: suppport collapse operator given as QobjEvo-type
139+
lindblad_dissipator(O::AbstractQuantumObject{DT,OperatorQuantumObject}, Id_cache = I(size(O, 1))) where {DT} =
140+
get_typename_wrapper(O)(_lindblad_dissipator(O.data, Id_cache), SuperOperator, O.dims)
107141

108142
# It is already a SuperOperator
109-
lindblad_dissipator(O::QuantumObject{DT,SuperOperatorQuantumObject}, Id_cache = nothing) where {DT} = O
143+
lindblad_dissipator(O::AbstractQuantumObject{DT,SuperOperatorQuantumObject}, Id_cache = nothing) where {DT} = O
110144

111145
@doc raw"""
112146
liouvillian(H::AbstractQuantumObject, c_ops::Union{Nothing,AbstractVector,Tuple}=nothing, Id_cache=I(prod(H.dims)))
@@ -134,7 +168,17 @@ function liouvillian(
134168
) where {DT,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}}
135169
L = liouvillian(H, Id_cache)
136170
if !(c_ops isa Nothing)
137-
L += mapreduce(lindblad_dissipator, +, c_ops)
171+
# sum all the Qobj first
172+
c_ops_ti = filter(op -> isa(op, QuantumObject), c_ops)
173+
if !isempty(c_ops_ti)
174+
L += mapreduce(op -> lindblad_dissipator(op, Id_cache), +, c_ops_ti)
175+
end
176+
177+
# sum rest of the QobjEvo together
178+
c_ops_td = filter(op -> isa(op, QuantumObjectEvolution), c_ops)
179+
if !isempty(c_ops_td)
180+
L += mapreduce(op -> lindblad_dissipator(op, Id_cache), +, c_ops_td)
181+
end
138182
end
139183
return L
140184
end

test/core-test/quantum_objects_evo.jl

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,9 @@
165165
a = destroy(N)
166166
coef1(p, t) = exp(-1im * p.ω1 * t)
167167
coef2(p, t) = sin(p.ω2 * t)
168+
coef3(p, t) = sin(p.ω3 * t)
168169
t = rand()
169-
p = (ω1 = rand(), ω2 = rand())
170+
p = (ω1 = rand(), ω2 = rand(), ω3 = rand())
170171

171172
# Operator
172173
H_td = QobjEvo(((a, coef1), a' * a, (a', coef2)))
@@ -180,12 +181,21 @@
180181
@test isoper(H_td) == true
181182

182183
# SuperOperator
183-
c_ops = [sqrt(rand()) * a]
184-
L_td = liouvillian(H_td, c_ops)
185-
L_td2 = -1im * spre(H_td) + 1im * spost(H_td) + lindblad_dissipator(c_ops[1])
184+
c_op1 = QobjEvo(((a', coef1),))
185+
c_op2 = QobjEvo(((a, coef2), (a * a', coef3)))
186+
c_ops = [c_op1, c_op2]
187+
D1_ti = abs2(coef1(p, t)) * lindblad_dissipator(a')
188+
D2_ti = @test_logs (:warn,) (:warn,) lindblad_dissipator(c_op2)(p, t)
189+
L_ti = liouvillian(H_ti) + D1_ti + D2_ti
190+
L_td = @test_logs (:warn,) (:warn,) liouvillian(H_td, c_ops)
186191
ρvec = mat2vec(rand_dm(N))
187-
@test L_td(p, t) L_td2(p, t)
188-
@test L_td(ρvec, p, t) L_td2(ρvec, p, t)
192+
@test L_td(p, t) L_ti
193+
# TODO: L_td here is ComposedOperator and need to setup cache first for the following test
194+
# TODO: (maybe can support `iscached` and `cache_operator` for QobjEvo in the future)
195+
# @test iscached(L_td) == false
196+
# @test L_td = cache_operator(L_td, ρvec)
197+
# @test iscached(L_td) == true
198+
# @test L_td(ρvec, p, t) ≈ L_ti * ρvec
189199
@test isconstant(L_td) == false
190200
@test issuper(L_td) == true
191201

0 commit comments

Comments
 (0)