@@ -11,8 +11,9 @@ mutable struct SuperOperator{B1,B2,T} <: AbstractSuperOperator{B1,B2}
1111 basis_r:: B2
1212 data:: T
1313 function SuperOperator {BL,BR,T} (basis_l:: BL , basis_r:: BR , data:: T ) where {BL,BR,T}
14- if length (basis_l[1 ])* length (basis_l[2 ]) != size (data, 1 ) ||
15- length (basis_r[1 ])* length (basis_r[2 ]) != size (data, 2 )
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 ))
1617 throw (DimensionMismatch (" Tried to assign data of size $(size (data)) to Hilbert spaces of sizes $(length .(basis_l)) , $(length .(basis_r)) " ))
1718 end
1819 new (basis_l, basis_r, data)
@@ -318,26 +319,72 @@ end
318319end
319320
320321# TODO should all of PauliTransferMatrix, ChiMatrix, ChoiState, and KrausOperators subclass AbstractSuperOperator?
322+
321323"""
322- Base class for the Choi representation of superoperators.
324+ KrausOperators(B1, B2, data)
325+
326+ Superoperator represented as a list of Kraus operators.
327+ Note unlike the SuperOperator or ChoiState types where
328+ its possible to have basis_l[1] != basis_l[2] and basis_r[1] != basis_r[2]
329+ which allows representations of maps between general linear operators defined on H_A \t o H_B,
330+ a quantum channel can only act on valid density operators which live in H_A \t o H_A.
331+ Thus the Kraus representation is only defined for quantum channels which map
332+ (H_A \t o H_A) \t o (H_B \t o H_B).
333+ """
334+ mutable struct KrausOperators{B1,B2,T} <: AbstractSuperOperator{B1,B2}
335+ basis_l:: B1
336+ basis_r:: B2
337+ data:: T
338+ function KrausOperators {BL,BR,T} (basis_l:: BL , basis_r:: BR , data:: T ) where {BL,BR,T}
339+ if (any (! samebases (basis_r, M. basis_r) for M in data) ||
340+ any (! samebases (basis_l, M. basis_l) for M in data))
341+ throw (DimensionMismatch (" Tried to assign data with incompatible bases" ))
342+ end
343+
344+ new (basis_l, basis_r, data)
345+ end
346+ end
347+ KrausOperators {BL,BR} (b1:: BL ,b2:: BR ,data:: T ) where {BL,BR,T} = KrausOperators {BL,BR,T} (b1,b2,data)
348+ KrausOperators (b1:: BL ,b2:: BR ,data:: T ) where {BL,BR,T} = KrausOperators {BL,BR,T} (b1,b2,data)
349+ KrausOperators (b,data) = KrausOperators (b,b,data)
350+
351+ function is_trace_preserving (kraus:: KrausOperators ; tol= 1e-9 )
352+ m = I (length (kraus. basis_r)) - sum (dagger (M)* M for M in kraus. data). data
353+ m[abs .(m) .< tol] .= 0
354+ return iszero (m)
355+ end
356+
357+ function is_valid_channel (kraus:: KrausOperators ; tol= 1e-9 )
358+ m = I (length (kraus. basis_r)) - sum (dagger (M)* M for M in kraus. data). data
359+ eigs = eigvals (Matrix (m))
360+ eigs[@. abs (eigs) < tol || eigs > 0 ] .= 0
361+ return iszero (eigs)
362+ end
363+
323364"""
365+ ChoiState(B1, B2, data)
324366
367+ Superoperator represented as a choi state stored as a sparse or dense matrix.
368+ """
325369mutable struct ChoiState{B1,B2,T} <: AbstractSuperOperator{B1,B2}
326370 basis_l:: B1
327371 basis_r:: B2
328372 data:: T
329- function ChoiState {BL,BR,T} (basis_l:: BL , basis_r:: BR , data:: T ) where {BL,BR,T}
373+ function ChoiState {BL,BR,T} (basis_l:: BL , basis_r:: BR , data:: T ; tol = 1e-9 ) where {BL,BR,T}
330374 if (length (basis_l) != 2 || length (basis_r) != 2 ||
331375 length (basis_l[1 ])* length (basis_l[2 ]) != size (data, 1 ) ||
332376 length (basis_r[1 ])* length (basis_r[2 ]) != size (data, 2 ))
333377 throw (DimensionMismatch (" Tried to assign data of size $(size (data)) to Hilbert spaces of sizes $(length .(basis_l)) , $(length .(basis_r)) " ))
334378 end
335- new (basis_l, basis_r, data)
379+ if any (abs .(data - data' ) .> tol)
380+ @warn " Trying to construct ChoiState from non-hermitian data"
381+ end
382+ new (basis_l, basis_r, Hermitian (data))
336383 end
337384end
338- ChoiState {BL,BR} (b1:: BL ,b2:: BR ,data:: T ) where {BL,BR,T} = ChoiState {BL,BR,T} (b1,b2,data)
339- ChoiState (b1:: BL ,b2:: BR ,data:: T ) where {BL,BR,T} = ChoiState {BL,BR,T} (b1,b2,data)
340- ChoiState (b,data) = ChoiState (b,b,data)
385+ ChoiState {BL,BR} (b1:: BL ,b2:: BR ,data:: T ; tol = 1e-9 ) where {BL,BR,T} = ChoiState {BL,BR,T} (b1,b2,data;tol = tol )
386+ ChoiState (b1:: BL ,b2:: BR ,data:: T ; tol = 1e-9 ) where {BL,BR,T} = ChoiState {BL,BR,T} (b1,b2,data; tol = tol )
387+ ChoiState (b,data; tol = tol ) = ChoiState (b,b,data; tol = tol )
341388
342389# TODO : document why we have super_to_choi return non-trace one density matrices.
343390# https://forest-benchmarking.readthedocs.io/en/latest/superoperator_representations.html
@@ -367,5 +414,29 @@ function _super_choi((r2, l2), (r1, l1), data::SparseMatrixCSC)
367414 return (l1, l2), (r1, r2), sparse (data)
368415end
369416
370- ChoiState (op:: SuperOperator ) = ChoiState (_super_choi (op. basis_l, op. basis_r, op. data)... )
417+ ChoiState (op:: SuperOperator ; tol= 1e-9 ) = ChoiState (_super_choi (op. basis_l, op. basis_r, op. data)... ; tol= tol)
418+ SuperOperator (kraus:: KrausOperators ) =
419+ SuperOperator ((kraus. basis_l, kraus. basis_l), (kraus. basis_r, kraus. basis_r),
420+ (sum (conj (op)⊗ op for op in kraus. data)). data)
421+
371422SuperOperator (op:: ChoiState ) = SuperOperator (_super_choi (op. basis_l, op. basis_r, op. data)... )
423+ ChoiState (kraus:: KrausOperators ) = ChoiState (SuperOperator (kraus))
424+
425+ function KrausOperators (choi:: ChoiState ; tol= 1e-9 )
426+ if (! samebases (choi. basis_l[1 ], choi. basis_l[2 ]) ||
427+ ! samebases (choi. basis_r[1 ], choi. basis_r[2 ]))
428+ throw (DimensionMismatch (" Tried to convert choi state of something that isn't a quantum channel mapping density operators to density operators" ))
429+ end
430+ bl, br = choi. basis_l[1 ], choi. basis_r[1 ]
431+ # ishermitian(choi.data) || @warn "ChoiState is not hermitian"
432+ # TODO : figure out how to do this with sparse matrices using e.g. Arpack.jl or ArnoldiMethod.jl
433+ vals, vecs = eigen (Hermitian (Matrix (choi. data)))
434+ for val in vals
435+ (abs (val) > tol && val < 0 ) && @warn " eigval $(val) < 0 but abs(eigval) > tol=$(tol) "
436+ end
437+ ops = [Operator (bl, br, sqrt (val)* reshape (vecs[:,i], length (bl), length (br)))
438+ for (i, val) in enumerate (vals) if abs (val) > tol && val > 0 ]
439+ return KrausOperators (bl, br, ops)
440+ end
441+
442+ KrausOperators (op:: SuperOperator ; tol= 1e-9 ) = KrausOperators (ChoiState (op; tol= tol); tol= tol)
0 commit comments