@@ -5,7 +5,7 @@ Functions for generating (common) quantum super-operators.
55export 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
4377The 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"""
4581spre (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
6096The 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"""
62100spost (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
68106Returns the [`SuperOperator`](@ref) form of `A` and `B` acting on the left and right of the density matrix operator, respectively: ``\m athcal{O} \l eft( \h at{A}, \h at{B} \r ight) \l eft[ \h at{\r ho} \r ight] = \h at{A} \h at{\r ho} \h at{B}``.
69107
@@ -77,16 +115,15 @@ Since the density matrix is vectorized in [`OperatorKet`](@ref) form: ``|\hat{\r
77115See also [`spre`](@ref) and [`spost`](@ref).
78116"""
79117function 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)
86123end
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
91128Returns 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
100137See 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
140184end
0 commit comments