Skip to content

Commit 0095240

Browse files
committed
More WIP pauli
1 parent aea201e commit 0095240

File tree

2 files changed

+110
-81
lines changed

2 files changed

+110
-81
lines changed

src/pauli.jl

Lines changed: 48 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,74 @@
11
using TransmuteDims
22

3-
const PauliTransferType = Operator{<:PauliBasis,<:PauliBasis}
3+
#function _pauli_to_ketbra1()
4+
# b = SpinBasis(1//2)
5+
# vec_it(fn) = vec(fn(b).data)
6+
# p2kb = hcat(map(vec_it, [identityoperator, sigmax, sigmay, sigmaz])...)
7+
#end
8+
#
9+
#function _ketbra_to_pauli(N)
10+
# T = kron((_pauli_to_ketbra1 for _=1:N)...)
11+
# T = reshape(T, Tuple(4 for _=1:2N))
12+
# T = PermutedDimsArray(T, ((2i-1 for i=1:N)..., (2i for i=1:N)...))
13+
# reshape(T, (4^N, 4^N))
14+
#end
15+
#
16+
#function _op_to_pauli(Nl, Nr, data)
17+
# Ul = ket_bra_to_pauli(Nl)
18+
# Ur = Nl == Nr ? Ul : _ketbra_to_pauli(Nr)
19+
# data = dagger(Ul) * data * Ur # TODO figure out normalization
20+
# @assert isapprox(imag.(data), zero(data), atol=tol)
21+
# Operator(PauliBasis()^Nl, PauliBasis()^Nr, real.(data))
22+
#end
423

5-
# TODO should either of these functions be cached?
6-
function _pauli_to_ketbra1()
24+
function _pauli_to_comp1()
725
b = SpinBasis(1//2)
826
vec_it(fn) = vec(fn(b).data)
9-
p2kb = hcat(map(vec_it, [identityoperator, sigmax, sigmay, sigmaz])...)
27+
V = hcat(map(vec_it, [identityoperator, sigmax, sigmay, sigmaz])...)
28+
Operator(PauliBasis(), KetBraBasis(b, b), V)
1029
end
1130

12-
function _ketbra_to_pauli(N)
13-
T = kron((_pauli_to_ketbra1 for _=1:N)...)
14-
T = reshape(T, Tuple(4 for _=1:2N))
15-
T = PermutedDimsArray(T, ((2i-1 for i=1:N)..., (2i for i=1:N)...))
16-
reshape(T, (4^N, 4^N))
17-
end
18-
19-
function _op_to_pauli(Nl, Nr, data)
20-
Ul = ket_bra_to_pauli(Nl)
21-
Ur = Nl == Nr ? Ul : _ketbra_to_pauli(Nr)
22-
data = dagger(Ul) * data * Ur # TODO figure out normalization
23-
@assert isapprox(imag.(data), zero(data), atol=tol)
24-
Operator(PauliBasis()^Nl, PauliBasis()^Nr, real.(data))
25-
end
31+
_pauli_to_comp1_cached = _pauli_to_comp1()
2632

33+
# TODO should this be further cached?
2734
"""
2835
comp_to_pauli(N)
2936
3037
Creates a superoperator which changes from the computational `SpinBasis(1//2)`
3138
to the `PauliBasis()` over `N` qubits.
3239
"""
33-
function comp_to_pauli(N)
34-
T = kron((_pauli_to_ketbra1 for _=1:N)...)
35-
T = reshape(T, Tuple(4 for _=1:2N))
36-
T = PermutedDimsArray(T, ((2i-1 for i=1:N)..., (2i for i=1:N)...))
37-
sb = SpinBasis(1//2)^N
38-
Operator(PauliBasis()^N, KetBraBasis(sb, sb), reshape(T, (4^N, 4^N))
40+
function pauli_to_comp(N::Integer)
41+
N > 0 || throw(ArgumentError())
42+
N == 1 && return _pauli_to_comp1_cached
43+
V = pauli_to_comp(N÷2)
44+
(N%2 == 0) && return VV
45+
return VVpauli_to_comp(1)
3946
end
4047

41-
function pauli(op::SuperOperatorType; tol=1e-9)
42-
bl, br = basis_l(op), basis_r(op)
43-
((basis_l(bl) == basis_r(bl)) && (basis_l(br) == basis_r(br))) || throw(ArgumentError("Superoperator must map between square operators in order to be converted to pauli represenation"))
44-
45-
for b in (basis_l(bl), basis_l(br))
46-
for i=1:length(b)
47-
(b[i] isa SpinBasis && dimension(b[i]) == 2) || throw(ArgumentError("Superoperator must be over systems composed of SpinBasis(1//2) to be converted to pauli representation"))
48-
end
48+
function _check_is_spinbasis(b)
49+
for i=1:length(b)
50+
(b[i] isa SpinBasis && dimension(b[i]) == 2) || throw(ArgumentError("Superoperator must be over systems composed of SpinBasis(1//2) to be converted to pauli representation"))
4951
end
52+
end
53+
54+
function pauli(op::SOpKetBraType)
55+
((basis_l(basis_l(op)) == basis_r(basis_l(op))) && (basis_l(br) == basis_r(basis_r(op)))) || throw(ArgumentError("Superoperator must map between square operators in order to be converted to pauli represenation"))
56+
bl, br = basis_l(basis_l(op)), basis_l(basis_r(op))
57+
foreach(_check_is_spinbasis, (bl, br))
5058

5159
Nl, Nr = length(basis_l(bl)), length(basis_l(br))
52-
Ul = ket_bra_to_pauli(Nl)
53-
Ur = Nl == Nr ? Ul : _ketbra_to_pauli(Nr)
54-
data = dagger(Ul)*op.data*Ur # TODO figure out normalization
55-
@assert isapprox(imag.(data), zero(data), atol=tol)
56-
Operator(PauliBasis()^Nl, PauliBasis()^Nr, real.(data))
60+
Vl = pauli_to_comp(Nl)
61+
Vr = Nl == Nr ? Vl : pauli_to_comp(Nr)
62+
#data = dagger(Ul)*op.data*Ur # TODO figure out normalization
63+
#@assert isapprox(imag.(data), zero(data), atol=tol)
64+
#Operator(PauliBasis()^Nl, PauliBasis()^Nr, real.(data))
65+
dagger(Vl) * op * Vr # TODO figure out normalization
5766
end
5867

59-
function chi(op::ChoiStateType; tol=1e-9)
68+
function chi(op::ChoiStateType)
6069
(basis_l(op) == basis_r(op)) || throw(ArgumentError("Choi state must map between square operators in order to be converted to chi represenation"))
61-
6270
bl, br = basis_l(basis_l(op)), basis_r(basis_l(op))
63-
for b in (bl, br)
64-
for i=1:length(b)
65-
(b[i] isa SpinBasis && dimension(b[i]) == 2) || throw(ArgumentError("Choi state must be over systems composed of SpinBasis(1//2) to be converted to chi representation"))
66-
end
67-
end
71+
foreach(_check_is_spinbasis, (bl, br))
6872

6973
Nl, Nr = length(bl), length(br)
7074
Ul = ket_bra_to_pauli(Nl)

src/superoperators.jl

Lines changed: 62 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,31 @@
1-
import QuantumInterface: KetBraBasis, ChoiBasis
1+
import QuantumInterface: KetBraBasis, ChoiBasis, PauliBasis
22
using TensorCast
33

4-
const SuperKetType = Ket{<:KetBraBasis}
5-
6-
const DenseSuperOpPureType{BL,BR} = Operator{<:KetBraBasis,<:KetBraBasis,<:Matrix}
7-
const DenseSuperOpAdjType{BL,BR} = Operator{<:KetBraBasis,<:KetBraBasis,<:Adjoint{<:Number,<:Matrix}}
8-
const DenseSuperOpType{BL,BR} = Union{DenseOpPureType{<:KetBraBasis,<:KetBraBasis},DenseOpAdjType{<:KetBraBasis,BR}}
9-
const SparseSuperOpPureType{BL,BR} = Operator{<:KetBraBasis,<:KetBraBasis,<:SparseMatrixCSC}
10-
const SparseSuperOpAdjType{BL,BR} = Operator{<:KetBraBasis,<:KetBraBasis,<:Adjoint{<:Number,<:SparseMatrixCSC}}
11-
const SparseSuperOpType{BL,BR} = Union{SparseOpPureType{<:KetBraBasis,<:KetBraBasis},SparseOpAdjType{<:KetBraBasis,BR}}
12-
13-
const SuperOperatorType = Operator{<:KetBraBasis,<:KetBraBasis}
14-
const ChoiStateType = Operator{<:ChoiBasis,<:ChoiBasis}
15-
16-
#const ChoiBasisType = Union{CompositeBasis{ChoiBasis,T} where {T}, CompositeBasis{ChoiBasis{B},T} where {B,T}}
17-
#const ChoiStateType = Operator{ChoiBasisType,ChoiBasisType}
18-
#const ChoiStateType = Union{Operator{CompositeBasis{ChoiBasis,S},CompositeBasis{ChoiBasis,T}} where {S,T}, Operator{CompositeBasis{ChoiBasis{BL},S},CompositeBasis{ChoiBasis{BR},T}} where {BL,BR,S,T}}
4+
const SOpBasis = Union{KetBraBasis, PauliBasis}
5+
const SuperOperatorType{BL,BR,T} = Operator{BL,BR,T} where {BL<:SOpBasis,BR<:SOpBasis}
6+
const SOpKetBraType{BL,BR,T} = Operator{BL,BR,T} where {BL<:KetBraBasis,BR<:KetBraBasis}
7+
const SOpPauliType{BL,BR,T} = Operator{BL,BR,T} where {BL<:PauliBasis,BR<:PauliBasis}
8+
const ChoiStateType{BL,BR,T} = Operator{BL,BR,T} where {BR<:ChoiBasis,BL<:ChoiBasis}
9+
const ChoiKetBraType{BL,BR,T} = Operator{ChoiBasis{BL,BR},ChoiBasis{BL,BR},T} where {BL<:KetBraBasis,BR<:KetBraBasis}
10+
const ChiType{BL,BR,T} = Operator{ChoiBasis{BL,BR},ChoiBasis{BL,BR},T} where {BL<:PauliBasis,BR<:PauliBasis}
11+
12+
const DenseSuperOpPureType{BL,BR} = SuperOperatorType{BL,BR,<:Matrix}
13+
const DenseSuperOpAdjType{BL,BR} = SuperOperatorType{BL,BR,<:Adjoint{<:Number,<:Matrix}}
14+
const DenseSuperOpType{BL,BR} = Union{DenseOpPureType{BL,BL},DenseOpAdjType{BL,BR}}
15+
const SparseSuperOpPureType{BL,BR} = SuperOperatorType{BL,BR,<:SparseMatrixCSC}
16+
const SparseSuperOpAdjType{BL,BR} = SuperOperatorType{BL,BR,<:Adjoint{<:Number,<:SparseMatrixCSC}}
17+
const SparseSuperOpType{BL,BR} = Union{SparseOpPureType{BL,BR},SparseOpAdjType{BL,BR}}
1918

2019
vec(op::Operator) = Ket(KetBraBasis(basis_l(op), basis_r(op)), vec(op.data))
21-
function unvec(k::SuperKetType)
22-
bl, br = basis_l(basis(k)), basis_r(basis(k))
23-
Operator(bl, br, reshape(k.data, dimension(bl), dimension(br)))
24-
end
25-
#function unvec(k::SuperKetType)
20+
#function unvec(k::Ket{<:KetBraBasis})
2621
# bl, br = basis_l(basis(k)), basis_r(basis(k))
27-
# @cast A[n,m] |= k.data[(n,m)] (n ∈ 1:dimension(bl), m ∈ 1:dimension(br))
28-
# return Operator(bl, br, A)
22+
# Operator(bl, br, reshape(k.data, dimension(bl), dimension(br)))
2923
#end
24+
function unvec(k::Ket{<:KetBraBasis})
25+
bl, br = basis_l(basis(k)), basis_r(basis(k))
26+
@cast A[n,m] |= k.data[(n,m)] (n 1:dimension(bl), m 1:dimension(br))
27+
return Operator(bl, br, A)
28+
end
3029

3130
function spre(op::Operator)
3231
multiplicable(op, op) || throw(ArgumentError("It's not clear what spre of a non-square operator should be. See issue #113"))
@@ -37,40 +36,66 @@ function spost(op::Operator)
3736
multiplicable(op, op) || throw(ArgumentError("It's not clear what spost of a non-square operator should be. See issue #113"))
3837
sprepost(identityoperator(op), op)
3938
end
40-
#function sprepost(A::Operator, B::Operator)
41-
# @cast C[(ν,μ), (n,m)] |= A.data[ν,n] * B.data[m,μ]
42-
# Operator(KetBraBasis(basis_l(A), basis_r(B)), KetBraBasis(basis_r(A), basis_l(B)), C)
43-
#end
4439

4540
#sprepost(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))
46-
4741
function sprepost(A::Operator, B::Operator)
4842
@cast C[(ν,μ), (n,m)] |= A.data[ν,n] * B.data[m,μ]
4943
Operator(KetBraBasis(basis_l(A), basis_r(B)), KetBraBasis(basis_r(A), basis_l(B)), C)
5044
end
5145

52-
function _super_choi((l1, l2), (r1, r2), data)
53-
data = Base.ReshapedArray(data, map(length, (l2, l1, r2, r1)), ())
54-
(l1, l2), (r1, r2) = (r2, l2), (r1, l1)
55-
data = PermutedDimsArray(data, (1, 3, 2, 4))
56-
data = Base.ReshapedArray(data, map(length, (l1l2, r1r2)), ())
57-
return (l1, l2), (r1, r2), copy(data)
46+
function tensor(A::SuperOperatorType, B::SuperOperatorType)
47+
a1, a2 = basis_l(A), basis_r(A)
48+
b1, b2 = basis_l(B), basis_r(B)
49+
da1, da2, db1, db2 = map(dimension, (a1, a2, b1, b2))
50+
@cast A[(ν,μ), (n,m)] |= A[m,μ] * B[n,ν] (m 1:da1, μ 1:da2, n 1:db1, ν 1:db2)
51+
return Operator(a1b2, a2b2, A)
5852
end
5953

60-
# Sec IV.A. of https://arxiv.org/abs/1111.6950
54+
#function _sch(data, l1, l2, r1, r2)
55+
# data = reshape(data, map(dimension, (l1, l2, r1, r2)))
56+
# data = permutedims(data, (4, 2, 3, 1))
57+
# reshape(data, map(dimension, (l2⊗r2, l1⊗r1)))
58+
#end
59+
#
60+
#function _sch(data::SparseMatrixCSC, l1, l2, r1, r2)
61+
# #data = reshape(sparse(data), map(dimension, (l1, l2, r1, r2)), ())
62+
# #data = _permutedims(sparse(data), size(data), (4, 2, 3, 1))
63+
# data = _permutedims(sparse(data), map(dimension, (l1, l2, r1, r2)), (4, 2, 3, 1))
64+
# sparse(reshape(data, map(dimension, (l2⊗r2, l1⊗r1))))
65+
# # sparse(::ReshapedArray) only works when ndims == 2
66+
#end
67+
68+
#sprepost(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))
69+
70+
#function _super_choi((l1, l2), (r1, r2), data)
71+
# data = Base.ReshapedArray(data, map(length, (l2, l1, r2, r1)), ())
72+
# (l1, l2), (r1, r2) = (r2, l2), (r1, l1)
73+
# data = PermutedDimsArray(data, (1, 3, 2, 4))
74+
# data = Base.ReshapedArray(data, map(length, (l1⊗l2, r1⊗r2)), ())
75+
# return (l1, l2), (r1, r2), copy(data)
76+
#end
77+
78+
# Sec IV.A. of https://arxiv.org/abs/1111.6950
6179
function _super_choi(basis_fn, op)
6280
l1, l2 = basis_l(basis_l(op)), basis_r(basis_l(op))
6381
r1, r2 = basis_l(basis_r(op)), basis_r(basis_r(op))
64-
d1, d2, d3, d4 = map(dimension, (l1, l2, r1, r2))
65-
@cast A[(ν,μ), (n,m)] |= op.data[(m,μ), (n,ν)] (m 1:d1, μ 1:d2, n 1:d3, ν 1:d4)
82+
# data = _sch(op.data, l1, l2, r1, r2)
83+
# data = reshape(op.data, map(dimension, (l1, l2, r1, r2)))
84+
# data = permutedims(data, (4, 2, 3, 1))
85+
# data = reshape(data, map(dimension, (l2⊗r2, l1⊗r1)))
86+
dl1, dl2, dr1, dr2 = map(dimension, (l1, l2, r1, r2))
87+
@cast A[(ν,μ), (n,m)] |= op.data[(m,μ), (n,ν)] (m 1:dl1, μ 1:dl2, n 1:dr1, ν 1:dr2)
6688
return Operator(basis_fn(r2, l2), basis_fn(r1, l1), A)
6789
end
6890

6991
choi(op::SuperOperatorType) = _super_choi(ChoiBasis, op)
7092
super(op::ChoiStateType) = _super_choi(KetBraBasis, op)
7193

94+
# I'm not sure this is actually right... see sec V.C. of https://arxiv.org/abs/1111.6950
7295
dagger(a::ChoiStateType) = choi(dagger(super(a)))
7396

97+
# This method is necessary so we don't fall back to the method below it
98+
*(a::SuperOperatorType, b::SuperOperatorType) = (check_multiplicable(a,b); Operator(a.basis_l, b.basis_r, a.data*b.data))
7499
*(a::SuperOperatorType, b::Operator) = unvec(a*vec(b))
75100
*(a::ChoiStateType, b::SuperOperatorType) = super(a)*b
76101
*(a::SuperOperatorType, b::ChoiStateType) = a*super(b)

0 commit comments

Comments
 (0)