1- import QuantumInterface: AbstractSuperOperator
2- import FastExpm: fastExpm
1+ import LinearAlgebra: vec
32
4- """
5- SuperOperator <: AbstractSuperOperator
3+ const SuperOperatorType = Operator{ <: KetBraBasis , <: KetBraBasis }
4+ const ChoiStateType = Operator{CompositeBasis{ <: Integer , <: Choi },CompositeBasis{ <: Integer , <: Choi }}
65
7- SuperOperator stored as representation, e.g. as a Matrix.
8- """
9- mutable struct SuperOperator{B1,B2,T} <: AbstractSuperOperator
10- basis_l:: B1
11- basis_r:: B2
12- data:: T
13- function SuperOperator {BL,BR,T} (basis_l:: BL , basis_r:: BR , data:: T ) where {BL,BR,T}
14- if (length (basis_l) != 2 || length (basis_r) != 2 ||
15- length (basis_l[1 ])* length (basis_l[2 ]) != size (data, 1 ) ||
16- length (basis_r[1 ])* length (basis_r[2 ]) != size (data, 2 ))
17- throw (DimensionMismatch (" Tried to assign data of size $(size (data)) to Hilbert spaces of sizes $(length .(basis_l)) , $(length .(basis_r)) " ))
18- end
19- new (basis_l, basis_r, data)
20- end
21- end
22- SuperOperator {BL,BR} (b1:: BL ,b2:: BR ,data:: T ) where {BL,BR,T} = SuperOperator {BL,BR,T} (b1,b2,data)
23- SuperOperator (b1:: BL ,b2:: BR ,data:: T ) where {BL,BR,T} = SuperOperator {BL,BR,T} (b1,b2,data)
24- SuperOperator (b,data) = SuperOperator (b,b,data)
25-
26- const DenseSuperOpType{BL,BR} = SuperOperator{BL,BR,<: Matrix }
27- const SparseSuperOpType{BL,BR} = SuperOperator{BL,BR,<: SparseMatrixCSC }
28-
29- """
30- DenseSuperOperator(b1[, b2, data])
31- DenseSuperOperator([T=ComplexF64,], b1[, b2])
32-
33- SuperOperator stored as dense matrix.
34- """
35- DenseSuperOperator (basis_l,basis_r,data) = SuperOperator (basis_l, basis_r, Matrix (data))
36- function DenseSuperOperator (:: Type{T} , basis_l, basis_r) where T
37- Nl = length (basis_l[1 ])* length (basis_l[2 ])
38- Nr = length (basis_r[1 ])* length (basis_r[2 ])
39- data = zeros (T, Nl, Nr)
40- DenseSuperOperator (basis_l, basis_r, data)
41- end
42- DenseSuperOperator (basis_l, basis_r) = DenseSuperOperator (ComplexF64, basis_l, basis_r)
43- DenseSuperOperator (:: Type{T} , b) where T = DenseSuperOperator (T, b, b)
44- DenseSuperOperator (b) = DenseSuperOperator (b,b)
45-
46-
47- """
48- SparseSuperOperator(b1[, b2, data])
49- SparseSuperOperator([T=ComplexF64,], b1[, b2])
50-
51- SuperOperator stored as sparse matrix.
52- """
53- SparseSuperOperator (basis_l, basis_r, data) = SuperOperator (basis_l, basis_r, sparse (data))
54-
55- function SparseSuperOperator (:: Type{T} , basis_l, basis_r) where T
56- Nl = length (basis_l[1 ])* length (basis_l[2 ])
57- Nr = length (basis_r[1 ])* length (basis_r[2 ])
58- data = spzeros (T, Nl, Nr)
59- SparseSuperOperator (basis_l, basis_r, data)
60- end
61- SparseSuperOperator (basis_l, basis_r) = SparseSuperOperator (ComplexF64, basis_l, basis_r)
62- SparseSuperOperator (:: Type{T} , b) where T = SparseSuperOperator (T, b, b)
63- SparseSuperOperator (b) = DenseSuperOperator (b,b)
64-
65- Base. copy (a:: T ) where {T<: SuperOperator } = T (a. basis_l, a. basis_r, copy (a. data))
66-
67- dense (a:: SuperOperator ) = DenseSuperOperator (a. basis_l, a. basis_r, a. data)
68- sparse (a:: SuperOperator ) = SuperOperator (a. basis_l, a. basis_r, sparse (a. data))
69-
70- == (a:: SuperOperator{B1,B2} , b:: SuperOperator{B1,B2} ) where {B1,B2} = (samebases (a,b) && a. data == b. data)
71- == (a:: SuperOperator , b:: SuperOperator ) = false
72-
73- Base. length (a:: SuperOperator ) = length (a. basis_l[1 ])* length (a. basis_l[2 ])* length (a. basis_r[1 ])* length (a. basis_r[2 ])
74- samebases (a:: SuperOperator , b:: SuperOperator ) = samebases (a. basis_l[1 ], b. basis_l[1 ]) && samebases (a. basis_l[2 ], b. basis_l[2 ]) &&
75- samebases (a. basis_r[1 ], b. basis_r[1 ]) && samebases (a. basis_r[2 ], b. basis_r[2 ])
76- multiplicable (a:: SuperOperator , b:: SuperOperator ) = multiplicable (a. basis_r[1 ], b. basis_l[1 ]) && multiplicable (a. basis_r[2 ], b. basis_l[2 ])
77- multiplicable (a:: SuperOperator , b:: AbstractOperator ) = multiplicable (a. basis_r[1 ], b. basis_l) && multiplicable (a. basis_r[2 ], b. basis_r)
78-
79-
80- # Arithmetic operations
81- function * (a:: SuperOperator{B1,B2} , b:: Operator{BL,BR} ) where {BL,BR,B1,B2<: Tuple{BL,BR} }
82- data = a. data* reshape (b. data, length (b. data))
83- return Operator (a. basis_l[1 ], a. basis_l[2 ], reshape (data, length (a. basis_l[1 ]), length (a. basis_l[2 ])))
84- end
85-
86- function * (a:: SuperOperator{B1,B2} , b:: SuperOperator{B2,B3} ) where {B1,B2,B3}
87- return SuperOperator {B1,B3} (a. basis_l, b. basis_r, a. data* b. data)
88- end
89-
90- * (a:: SuperOperator , b:: Number ) = SuperOperator (a. basis_l, a. basis_r, a. data* b)
91- * (a:: Number , b:: SuperOperator ) = b* a
92-
93- / (a:: SuperOperator , b:: Number ) = SuperOperator (a. basis_l, a. basis_r, a. data ./ b)
94-
95- + (a:: SuperOperator{B1,B2} , b:: SuperOperator{B1,B2} ) where {B1,B2} = SuperOperator {B1,B2} (a. basis_l, a. basis_r, a. data+ b. data)
96- + (a:: SuperOperator , b:: SuperOperator ) = throw (IncompatibleBases ())
97-
98- - (a:: SuperOperator{B1,B2} , b:: SuperOperator{B1,B2} ) where {B1,B2} = SuperOperator {B1,B2} (a. basis_l, a. basis_r, a. data- b. data)
99- - (a:: SuperOperator ) = SuperOperator (a. basis_l, a. basis_r, - a. data)
100- - (a:: SuperOperator , b:: SuperOperator ) = throw (IncompatibleBases ())
101-
102- identitysuperoperator (b:: Basis ) =
103- SuperOperator ((b,b), (b,b), Eye {ComplexF64} (length (b)^ 2 ))
104-
105- identitysuperoperator (op:: DenseSuperOpType ) =
106- SuperOperator (op. basis_l, op. basis_r, Matrix (one (eltype (op. data))I, size (op. data)))
107-
108- identitysuperoperator (op:: SparseSuperOpType ) =
109- SuperOperator (op. basis_l, op. basis_r, sparse (one (eltype (op. data))I, size (op. data)))
110-
111- dagger (x:: DenseSuperOpType ) = SuperOperator (x. basis_r, x. basis_l, copy (adjoint (x. data)))
112- dagger (x:: SparseSuperOpType ) = SuperOperator (x. basis_r, x. basis_l, sparse (adjoint (x. data)))
113-
114-
115- """
116- spre(op)
117-
118- Create a super-operator equivalent for right side operator multiplication.
119-
120- For operators ``A``, ``B`` the relation
121-
122- ```math
123- \\ mathrm{spre}(A) B = A B
124- ```
125-
126- holds. `op` can be a dense or a sparse operator.
127- """
128- function spre (op:: AbstractOperator )
129- if ! multiplicable (op, op)
130- throw (ArgumentError (" It's not clear what spre of a non-square operator should be. See issue #113" ))
131- end
132- SuperOperator ((op. basis_l, op. basis_l), (op. basis_r, op. basis_r), tensor (op, identityoperator (op)). data)
133- end
134-
135- """
136- spost(op)
137-
138- Create a super-operator equivalent for left side operator multiplication.
139-
140- For operators ``A``, ``B`` the relation
6+ vec (op:: Operator ) = Ket (KetBraBasis (basis_l (op), basis_r (op)), reshape (op. data, length (op. data)))
1417
142- ```math
143- \\ mathrm{spost}(A) B = B A
144- ```
145-
146- holds. `op` can be a dense or a sparse operator.
147- """
148- function spost (op:: AbstractOperator )
149- if ! multiplicable (op, op)
150- throw (ArgumentError (" It's not clear what spost of a non-square operator should be. See issue #113" ))
151- end
152- SuperOperator ((op. basis_r, op. basis_r), (op. basis_l, op. basis_l), kron (permutedims (op. data), identityoperator (op). data))
8+ function spre (op:: Operator )
9+ multiplicable (op, op) || throw (ArgumentError (" It's not clear what spre of a non-square operator should be. See issue #113" ))
10+ Operator (KetBraBasis (basis_l (op)), KetBraBasis (basis_r (op)), tensor (op, identityoperator (op)). data)
15311end
15412
155- """
156- sprepost(op)
157-
158- Create a super-operator equivalent for left and right side operator multiplication.
159-
160- For operators ``A``, ``B``, ``C`` the relation
161-
162- ```math
163- \\ mathrm{sprepost}(A, B) C = A C B
164- ```
165-
166- holds. `A` ond `B` can be dense or a sparse operators.
167- """
168- sprepost (A:: AbstractOperator , B:: AbstractOperator ) = SuperOperator ((A. basis_l, B. basis_r), (A. basis_r, B. basis_l), kron (permutedims (B. data), A. data))
169-
170- function _check_input (H:: AbstractOperator , J:: Vector , Jdagger:: Vector , rates)
171- for j= J
172- @assert isa (j, AbstractOperator)
173- end
174- for j= Jdagger
175- @assert isa (j, AbstractOperator)
176- end
177- @assert length (J)== length (Jdagger)
178- if isa (rates, Matrix{<: Number })
179- @assert size (rates, 1 ) == size (rates, 2 ) == length (J)
180- elseif isa (rates, Vector{<: Number })
181- @assert length (rates) == length (J)
182- end
13+ function spost (op:: Operator )
14+ multiplicable (op, op) || throw (ArgumentError (" It's not clear what spost of a non-square operator should be. See issue #113" ))
15+ SuperOperator (KetBraBasis (basis_r (op)), (op. basis_l, op. basis_l), kron (permutedims (op. data), identityoperator (op). data))
18316end
18417
185-
186- """
187- liouvillian(H, J; rates, Jdagger)
188-
189- Create a super-operator equivalent to the master equation so that ``\\ dot ρ = S ρ``.
190-
191- The super-operator ``S`` is defined by
192-
193- ```math
194- S ρ = -\\ frac{i}{ħ} [H, ρ] + \\ sum_i J_i ρ J_i^† - \\ frac{1}{2} J_i^† J_i ρ - \\ frac{1}{2} ρ J_i^† J_i
195- ```
196-
197- # Arguments
198- * `H`: Hamiltonian.
199- * `J`: Vector containing the jump operators.
200- * `rates`: Vector or matrix specifying the coefficients for the jump operators.
201- * `Jdagger`: Vector containing the hermitian conjugates of the jump operators. If they
202- are not given they are calculated automatically.
203- """
204- function liouvillian (H, J; rates= ones (length (J)), Jdagger= dagger .(J))
205- _check_input (H, J, Jdagger, rates)
206- L = spre (- 1im * H) + spost (1im * H)
207- if isa (rates, AbstractMatrix)
208- for i= 1 : length (J), j= 1 : length (J)
209- jdagger_j = rates[i,j]/ 2 * Jdagger[j]* J[i]
210- L -= spre (jdagger_j) + spost (jdagger_j)
211- L += spre (rates[i,j]* J[i]) * spost (Jdagger[j])
212- end
213- elseif isa (rates, AbstractVector)
214- for i= 1 : length (J)
215- jdagger_j = rates[i]/ 2 * Jdagger[i]* J[i]
216- L -= spre (jdagger_j) + spost (jdagger_j)
217- L += spre (rates[i]* J[i]) * spost (Jdagger[i])
218- end
219- end
220- return L
221- end
222-
223- """
224- exp(op::DenseSuperOperator)
225-
226- Superoperator exponential which can, for example, be used to calculate time evolutions.
227- Uses LinearAlgebra's `Base.exp`.
228-
229- If you only need the result of the exponential acting on an operator,
230- consider using much faster implicit methods that do not calculate the entire exponential.
231- """
232- Base. exp (op:: DenseSuperOpType ) = DenseSuperOperator (op. basis_l, op. basis_r, exp (op. data))
233-
234- """
235- exp(op::SparseSuperOperator; opts...)
236-
237- Superoperator exponential which can, for example, be used to calculate time evolutions.
238- Uses [`FastExpm.jl.jl`](https://github.com/fmentink/FastExpm.jl) which will return a sparse
239- or dense operator depending on which is more efficient.
240- All optional arguments are passed to `fastExpm` and can be used to specify tolerances.
241-
242- If you only need the result of the exponential acting on an operator,
243- consider using much faster implicit methods that do not calculate the entire exponential.
244- """
245- function Base. exp (op:: SparseSuperOpType ; opts... )
246- if iszero (op)
247- return identitysuperoperator (op)
248- else
249- return SuperOperator (op. basis_l, op. basis_r, fastExpm (op. data; opts... ))
250- end
251- end
252-
253- # Array-like functions
254- Base. zero (A:: SuperOperator ) = SuperOperator (A. basis_l, A. basis_r, zero (A. data))
255- Base. size (A:: SuperOperator ) = size (A. data)
256- @inline Base. axes (A:: SuperOperator ) = axes (A. data)
257- Base. ndims (A:: SuperOperator ) = 2
258- Base. ndims (:: Type{<:SuperOperator} ) = 2
259-
260- # Broadcasting
261- Base. broadcastable (A:: SuperOperator ) = A
262-
263- # Custom broadcasting styles
264- struct SuperOperatorStyle{BL,BR} <: Broadcast.BroadcastStyle end
265- # struct DenseSuperOperatorStyle{BL,BR} <: SuperOperatorStyle{BL,BR} end
266- # struct SparseSuperOperatorStyle{BL,BR} <: SuperOperatorStyle{BL,BR} end
267-
268- # Style precedence rules
269- Broadcast. BroadcastStyle (:: Type{<:SuperOperator{BL,BR}} ) where {BL,BR} = SuperOperatorStyle {BL,BR} ()
270- # Broadcast.BroadcastStyle(::Type{<:SparseSuperOperator{BL,BR}}) where {BL,BR} = SparseSuperOperatorStyle{BL,BR}()
271- # Broadcast.BroadcastStyle(::DenseSuperOperatorStyle{B1,B2}, ::SparseSuperOperatorStyle{B1,B2}) where {B1,B2} = DenseSuperOperatorStyle{B1,B2}()
272- # Broadcast.BroadcastStyle(::DenseSuperOperatorStyle{B1,B2}, ::DenseSuperOperatorStyle{B3,B4}) where {B1,B2,B3,B4} = throw(IncompatibleBases())
273- # Broadcast.BroadcastStyle(::SparseSuperOperatorStyle{B1,B2}, ::SparseSuperOperatorStyle{B3,B4}) where {B1,B2,B3,B4} = throw(IncompatibleBases())
274- # Broadcast.BroadcastStyle(::DenseSuperOperatorStyle{B1,B2}, ::SparseSuperOperatorStyle{B3,B4}) where {B1,B2,B3,B4} = throw(IncompatibleBases())
275-
276- # Out-of-place broadcasting
277- @inline function Base. copy (bc:: Broadcast.Broadcasted{Style,Axes,F,Args} ) where {BL,BR,Style<: SuperOperatorStyle{BL,BR} ,Axes,F,Args<: Tuple }
278- bcf = Broadcast. flatten (bc)
279- bl,br = find_basis (bcf. args)
280- bc_ = Broadcasted_restrict_f (bcf. f, bcf. args, axes (bcf))
281- return SuperOperator {BL,BR} (bl, br, copy (bc_))
282- end
283- # @inline function Base.copy(bc::Broadcast.Broadcasted{Style,Axes,F,Args}) where {BL,BR,Style<:SparseSuperOperatorStyle{BL,BR},Axes,F,Args<:Tuple}
284- # bcf = Broadcast.flatten(bc)
285- # bl,br = find_basis(bcf.args)
286- # bc_ = Broadcasted_restrict_f(bcf.f, bcf.args, axes(bcf))
287- # return SuperOperator{BL,BR}(bl, br, copy(bc_))
288- # end
289- find_basis (a:: SuperOperator , rest) = (a. basis_l, a. basis_r)
290-
291- const BasicMathFunc = Union{typeof (+ ),typeof (- ),typeof (* ),typeof (/ )}
292- function Broadcasted_restrict_f (f:: BasicMathFunc , args:: Tuple{Vararg{<:SuperOperator}} , axes)
293- args_ = Tuple (a. data for a= args)
294- return Broadcast. Broadcasted (f, args_, axes)
295- end
296-
297- # In-place broadcasting
298- @inline function Base. copyto! (dest:: SuperOperator{BL,BR} , bc:: Broadcast.Broadcasted{Style,Axes,F,Args} ) where {BL,BR,Style<: SuperOperatorStyle{BL,BR} ,Axes,F,Args}
299- axes (dest) == axes (bc) || Base. Broadcast. throwdm (axes (dest), axes (bc))
300- # Performance optimization: broadcast!(identity, dest, A) is equivalent to copyto!(dest, A) if indices match
301- if bc. f === identity && isa (bc. args, Tuple{<: SuperOperator{BL,BR} }) # only a single input argument to broadcast!
302- A = bc. args[1 ]
303- if axes (dest) == axes (A)
304- return copyto! (dest, A)
305- end
306- end
307- # Get the underlying data fields of operators and broadcast them as arrays
308- bcf = Broadcast. flatten (bc)
309- bc_ = Broadcasted_restrict_f (bcf. f, bcf. args, axes (bcf))
310- copyto! (dest. data, bc_)
311- return dest
312- end
313- @inline Base. copyto! (A:: SuperOperator{BL,BR} ,B:: SuperOperator{BL,BR} ) where {BL,BR} = (copyto! (A. data,B. data); A)
314- @inline function Base. copyto! (dest:: SuperOperator{B1,B2} , bc:: Broadcast.Broadcasted{Style,Axes,F,Args} ) where {
315- B1,B2,B3,
316- B4,Style<: SuperOperatorStyle{B3,B4} ,Axes,F,Args
317- }
318- throw (IncompatibleBases ())
319- end
320-
321- """
322- ChoiState <: AbstractSuperOperator
323-
324- Superoperator represented as a choi state.
325- """
326- mutable struct ChoiState{B1,B2,T} <: AbstractSuperOperator
327- basis_l:: B1
328- basis_r:: B2
329- data:: T
330- function ChoiState {BL,BR,T} (basis_l:: BL , basis_r:: BR , data:: T ) where {BL,BR,T}
331- if (length (basis_l) != 2 || length (basis_r) != 2 ||
332- length (basis_l[1 ])* length (basis_l[2 ]) != size (data, 1 ) ||
333- length (basis_r[1 ])* length (basis_r[2 ]) != size (data, 2 ))
334- throw (DimensionMismatch (" Tried to assign data of size $(size (data)) to Hilbert spaces of sizes $(length .(basis_l)) , $(length .(basis_r)) " ))
335- end
336- new (basis_l, basis_r, data)
337- end
338- end
339- ChoiState (b1:: BL , b2:: BR , data:: T ) where {BL,BR,T} = ChoiState {BL,BR,T} (b1, b2, data)
340-
341- dense (a:: ChoiState ) = ChoiState (a. basis_l, a. basis_r, Matrix (a. data))
342- sparse (a:: ChoiState ) = ChoiState (a. basis_l, a. basis_r, sparse (a. data))
343- dagger (a:: ChoiState ) = ChoiState (dagger (SuperOperator (a)))
344- * (a:: ChoiState , b:: ChoiState ) = ChoiState (SuperOperator (a)* SuperOperator (b))
345- * (a:: ChoiState , b:: Operator ) = SuperOperator (a)* b
346- == (a:: ChoiState , b:: ChoiState ) = (SuperOperator (a) == SuperOperator (b))
18+ sprepost (A:: Operator , B:: Operator ) = SuperOperator ((A. basis_l, B. basis_r), (A. basis_r, B. basis_l), kron (permutedims (B. data), A. data))
34719
34820# reshape swaps within systems due to colum major ordering
34921# https://docs.qojulia.org/quantumobjects/operators/#tensor_order
@@ -369,9 +41,25 @@ function _super_choi((r2, l2), (r1, l1), data::SparseMatrixCSC)
36941 return (l1, l2), (r1, r2), sparse (data)
37042end
37143
372- ChoiState (op:: SuperOperator ) = ChoiState (_super_choi (op. basis_l, op. basis_r, op. data)... )
373- SuperOperator (op:: ChoiState ) = SuperOperator (_super_choi (op. basis_l, op. basis_r, op. data)... )
44+ function choi (op:: SuperOperatorType )
45+ bl, br = basis_l (op), basis_r (op)
46+ (l1, l2), (r1, r2) = (basis_l (bl), basis_r (bl)), (basis_l (br), basis_r (br))
47+ (l1, l2), (r1, r2), data = _super_choi ((l1, l2), (r1, r2), op. data)
48+ return Operator (ChoiBasis (l1,true )⊗ ChoiBasis (l2,false ),
49+ ChoiBasis (r1,true )⊗ ChoiBasis (r2,false ), data)
50+ end
51+
52+ function super (op:: ChoiStateType )
53+ bl, br = basis_l (op), basis_r (op)
54+ (l1, l2), (r1, r2) = (basis_l (bl), basis_r (bl)), (basis_l (br), basis_r (br))
55+ (l1, l2), (r1, r2), data = _super_choi ((l1, l2), (r1, r2), op. data)
56+ return Operator (KetBraBasis (l1,l2), KetBraBasis (r1,r2), data)
57+ end
37458
375- * (a:: ChoiState , b:: SuperOperator ) = SuperOperator (a)* b
376- * (a:: SuperOperator , b:: ChoiState ) = a* SuperOperator (b)
59+ dagger (a:: ChoiStateType ) = choi (dagger (super (a)))
37760
61+ * (a:: SuperOperatorType , b:: Operator ) = a* vec (b)
62+ * (a:: ChoiStateType , b:: SuperOperatorType ) = super (a)* b
63+ * (a:: SuperOperatorType , b:: ChoiStateType ) = a* super (b)
64+ * (a:: ChoiStateType , b:: ChoiStateType ) = choi (super (a)* super (b))
65+ * (a:: ChoiStateType , b:: Operator ) = super (a)* b
0 commit comments