1- import QuantumInterface: KetBraBasis, ChoiBasis
1+ import QuantumInterface: KetBraBasis, ChoiBasis, spre, spost
22
33const SuperOperatorType{BL,BR,T} = Operator{BL,BR,T} where {BL<: KetBraBasis ,BR<: KetBraBasis }
44const ChoiStateType{BL,BR,T} = Operator{BL,BR,T} where {BR<: ChoiBasis ,BL<: ChoiBasis }
@@ -11,20 +11,6 @@ function unvec(k::Ket{<:KetBraBasis})
1111 Operator (bl, br, reshape (k. data, dimension (bl), dimension (br)))
1212 # @cast A[n,m] |= k.data[(n,m)] (n ∈ 1:dimension(bl), m ∈ 1:dimension(br))
1313end
14- # function unvec(k::Ket{<:KetBraBasis})
15- # bl, br = basis_l(basis(k)), basis_r(basis(k))
16- # return Operator(bl, br, A)
17- # end
18-
19- function spre (op:: Operator )
20- multiplicable (op, op) || throw (ArgumentError (" It's not clear what spre of a non-square operator should be. See issue #113" ))
21- sprepost (op, identityoperator (op))
22- end
23-
24- function spost (op:: Operator )
25- multiplicable (op, op) || throw (ArgumentError (" It's not clear what spost of a non-square operator should be. See issue #113" ))
26- sprepost (identityoperator (op), op)
27- end
2814
2915sprepost (A:: Operator , B:: Operator ) = Operator (KetBraBasis (basis_l (A), basis_r (B)), KetBraBasis (basis_r (A), basis_l (B)), kron (permutedims (B. data), A. data))
3016# @cast C[(ν,μ), (n,m)] |= A.data[ν,n] * B.data[m,μ]
@@ -72,7 +58,7 @@ super(op::ChoiStateType) = _super_choi(KetBraBasis, op)
7258super (op:: SuperOperatorType ) = op
7359choi (op:: ChoiStateType ) = op
7460
75- # I'm not sure this is actually right ... see sec V.C. of https://arxiv.org/abs/1111.6950
61+ # Probably possible to do this directly ... see sec V.C. of https://arxiv.org/abs/1111.6950
7662dagger (a:: ChoiStateType ) = choi (dagger (super (a)))
7763
7864# This method is necessary so we don't fall back to the method below it
@@ -93,3 +79,41 @@ identitysuperoperator(op::DenseOpType{BL,BR}) where {BL<:KetBraBasis, BR<:KetBra
9379identitysuperoperator (op:: SparseOpType{BL,BR} ) where {BL<: KetBraBasis , BR<: KetBraBasis } =
9480 Operator (op. basis_l, op. basis_r, sparse (one (eltype (op. data))I, size (op. data)))
9581
82+
83+ """
84+ KrausOperators <: AbstractOperator
85+
86+ Superoperator represented as a list of Kraus operators.
87+
88+ Note that KrausOperators can only represent linear maps taking density operators to other
89+ (potentially unnormalized) density operators.
90+ In contrast the `SuperOperator` or `ChoiState` representations can represent arbitrary linear maps
91+ taking arbitrary operators defined on ``H_A \\ to H_B`` to ``H_C \\ to H_D``.
92+ In otherwords, the Kraus representation is only defined for completely positive linear maps of the form
93+ ``(H_A \\ to H_A) \\ to (H_B \\ to H_B)``.
94+ Thus converting from `SuperOperator` or `ChoiState` to `KrausOperators` will throw an exception if the
95+ map cannot be faithfully represented up to the specificed tolerance `tol`.
96+
97+ struct KrausOperators{B1,B2,T} <: AbstractSuperOperator{B1,B2}
98+ basis_l::B1
99+ basis_r::B2
100+ data::Vector{T}
101+ function KrausOperators(bl::BL, br::BR, data::Vector{T}) where {BL,BR,T}
102+ foreach(M -> check_samebases(br, basis_r(M)), data)
103+ foreach(M -> check_samebases(bl, basis_r(M)), data)
104+ new(basis_l, basis_r, data)
105+ end
106+ end
107+
108+ dagger(a::KrausOperators) = KrausOperators(a.basis_r, a.basis_l, [dagger(op) for op in a.data])
109+ *(a::KrausOperators, b::KrausOperators) =
110+ (check_samebases(a.basis_r, b.basis_l);
111+ KrausOperators(a.basis_l, b.basis_r, [A*B for A in a.data for B in b.data]))
112+ *(a::KrausOperators, b::AbstractOperator) = sum(op*b*dagger(op) for op in a.data)
113+ ==(a::KrausOperators, b::KrausOperators) = (super(a) == super(b))
114+ isapprox(a::KrausOperators, b::KrausOperators; kwargs...) = isapprox(SuperOperator(a), SuperOperator(b); kwargs...)
115+ tensor(a::KrausOperators, b::KrausOperators) =
116+ KrausOperators(a.basis_l ⊗ b.basis_l, a.basis_r ⊗ b.basis_r,
117+ [A ⊗ B for A in a.data for B in b.data])
118+
119+ """
0 commit comments