Skip to content

Commit 6a70809

Browse files
committed
More WIP Pauli
1 parent bbefb39 commit 6a70809

File tree

5 files changed

+211
-113
lines changed

5 files changed

+211
-113
lines changed

src/QuantumOpticsBase.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export Basis, GenericBasis, CompositeBasis, basis, basis_l, basis_r, dimension,
4242
KetBraBasis, ChoiBasis, PauliBasis, ChiBasis,
4343
vec, unvec, super, choi, kraus, stinespring, pauli, chi,
4444
spre, spost, sprepost, liouvillian, identitysuperoperator,
45-
SuperOperatorType, DenseSuperOpType, SparseSuperOpType,
45+
SuperOperatorType, ChoiStateType, PauliTransferType, ChiType,
4646
#fock
4747
FockBasis, number, destroy, create,
4848
fockstate, coherentstate, coherentstate!,

src/pauli.jl

Lines changed: 66 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,95 @@
1+
import QuantumInterface: PauliBasis, ChiBasis
2+
3+
const PauliTransferType{BL,BR,T} = Operator{BL,BR,T} where {BL<:PauliBasis,BR<:PauliBasis}
4+
const ChiType{BL,BR,T} = Operator{BL,BR,T} where {BL<:ChiBasis,BR<:ChiBasis}
15

26
# comp stands for computational basis
3-
function _pauli_comp_1(b_out_fn, b_in)
7+
function _pauli_comp_1()
48
b = SpinBasis(1//2)
59
vec_it(fn) = vec((fn(b)/sqrt(2)).data) # provides "standard" normalization
610
V = hcat(map(vec_it, [identityoperator, sigmax, sigmay, sigmaz])...)
7-
Operator(b_out_fn(b, b), b_in, V)
11+
Operator(KetBraBasis(b, b), PauliBasis(1), V)
812
end
913

10-
_pauli_comp_kb1_cached = _pauli_comp_1(KetBraBasis, PauliBasis(1))
11-
_pauli_comp_choi1_cached = _pauli_comp_1(ChoiBasis, ChiBasis(2))
14+
_pauli_comp_1_cached = _pauli_comp_1()
1215

1316
# TODO: should this be further cached?
1417
"""
15-
pauli_comp_kb(N)
18+
pauli_comp(N)
1619
1720
Creates a superoperator which changes from the computational `KetBra(SpinBasis(1//2))`
1821
to the `PauliBasis()` over `N` qubits.
1922
"""
20-
pauli_comp_kb(N::Integer) = tensor_pow(_pauli_comp_kb1_cached, N)
21-
pauli_comp_choi(N::Integer) = tensor_pow(_pauli_comp_choi1_cached, N)
23+
pauli_comp(N) = tensor_pow(_pauli_comp_1_cached, N)
24+
25+
"""
26+
pauli_comp(Nl,Nr)
27+
28+
Creates a superoperator which changes from a Choi state in the computational `SpinBasis(1//2)` with `Nl` in the reference system and `Nr` in the output system to a `ChiBasis(Nl,Nr)`.
29+
"""
30+
function choi_chi(Nl, Nr)
31+
@assert (Nl+Nr)%2 == 0
32+
b = SpinBasis(1//2)
33+
Operator(ChoiBasis(b^Nl, b^Nr), ChiBasis(Nl, Nr), pauli_comp((Nl+Nr)÷2).data)
34+
end
2235

2336
# It's possible to get better asympotic speedups using, e.g. methods from
2437
# https://iopscience.iop.org/article/10.1088/1402-4896/ad6499
2538
# https://arxiv.org/abs/2411.00526
2639
# https://quantum-journal.org/papers/q-2024-09-05-1461/ (see appendices)
27-
pauli(op::Operator) = dagger(pauli_comp_kb(length(basis(op)))) * vec(op)
28-
29-
function pauli(op::SOpKetBraType)
40+
function _pauli_comp_convert(op, rev)
3041
Nl, Nr = length(basis_l(basis_l(op))), length(basis_l(basis_r(op)))
31-
Vl = pauli_comp_kb(Nl)
32-
Vr = Nl == Nr ? Vl : pauli_comp_kb(Nr)
33-
dagger(Vl) * op * Vr
42+
Vl = pauli_comp(Nl)
43+
Vr = Nl == Nr ? Vl : pauli_comp(Nr)
44+
rev ? Vl * op * dagger(Vr) : dagger(Vl) * op * Vr
3445
end
3546

36-
function chi(op::ChoiStateType)
47+
function _choi_chi_convert(op, rev)
3748
Nl, Nr = length(basis_l(basis_l(op))), length(basis_r(basis_l(op)))
38-
Vl = pauli_comp_choi(Nl)
39-
Vr = Nl == Nr ? Vl : pauli_comp_choi(Nr)
40-
dagger(Vl) * op * Vr
41-
end
42-
43-
function _pauli_chi(basis_fn, op)
44-
bl, br = basis_l(op), basis_r(op)
45-
Nl, Nr = length(bl), length(br)
46-
data = reshape(op.data, (2^Nl, 2^Nl, 2^Nr, 2^Nr))
47-
data = PermutedDimsArray(data, (4, 2, 3, 1))
48-
data = reshape(data, (2^(Nl+Nr), 2^(Nl+Nr)))
49-
return Operator(basis_fn(Nl+Nr), basis_fn(Nl+Nr), data)
49+
V = choi_chi(Nl,Nr)
50+
rev ? V * op * dagger(V) : dagger(V) * op * V
5051
end
5152

52-
pauli(op::ChiType) = _pauli_chi(PauliBasis, op)
53-
chi(op::SOpPauliType) = _pauli_chi(ChiBasis, op)
53+
pauli(op::SuperOperatorType) = _pauli_comp_convert(op, false)
54+
super(op::PauliTransferType) = _pauli_comp_convert(op, true)
55+
chi(op::ChoiStateType) = _choi_chi_convert(op, false)
56+
choi(op::ChiType) = _choi_chi_convert(op, true)
57+
pauli(op::ChiType) = _super_choi(PauliBasis, op)
58+
chi(op::PauliTransferType) = _super_choi(ChiBasis, op)
5459
pauli(op::ChoiStateType) = pauli(chi(op))
55-
chi(op::SOpKetBraType) = chi(pauli(op))
60+
chi(op::SuperOperatorType) = chi(pauli(op))
61+
super(op::ChiType) = super(choi(op))
62+
choi(op::PauliTransferType) = choi(super(op))
63+
64+
pauli(op::PauliTransferType) = op
65+
chi(op::ChiType) = op
66+
67+
pauli(op::Operator) = pauli(vec(op))
68+
pauli(k::Ket{<:KetBraBasis}) = dagger(pauli_comp(length(basis_l(basis(k))))) * k
69+
unvec(k::Ket{<:PauliBasis}) = unvec(pauli_comp(length(basis_l(basis(k)))) * k)
70+
71+
# TODO: document return types of mixed superoperator multiplication...
72+
# This method is necessary so we don't fall back to the method below it
73+
*(a::PauliTransferType, b::PauliTransferType) = (check_multiplicable(a,b); Operator(a.basis_l, b.basis_r, a.data*b.data))
74+
*(a::PauliTransferType, b::Operator) = unvec(a*pauli(b))
75+
76+
*(a::ChiType, b::ChiType) = chi(pauli(a)*pauli(b))
77+
*(a::ChiType, b::Operator) = pauli(a)*b
78+
79+
*(a::PauliTransferType, b::SuperOperatorType) = super(a)*b
80+
*(a::SuperOperatorType, b::PauliTransferType) = a*super(b)
81+
82+
*(a::PauliTransferType, b::ChoiStateType) = a*chi(b)
83+
*(a::ChoiStateType, b::PauliTransferType) = chi(a)*b
84+
85+
*(a::SuperOperatorType, b::ChiType) = a*super(b)
86+
*(a::ChiType, b::SuperOperatorType) = super(a)*b
87+
88+
*(a::PauliTransferType, b::ChiType) = a*pauli(b)
89+
*(a::ChiType, b::PauliTransferType) = pauli(a)*b
90+
91+
*(a::ChoiStateType, b::ChiType) = a*choi(b)
92+
*(a::ChiType, b::ChoiStateType) = choi(a)*b
5693

5794
"""
5895
function hwpauli(op::SuperOperatorType; tol=1e-9)

src/superoperators.jl

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
1-
import QuantumInterface: KetBraBasis, ChoiBasis, PauliBasis, ChiBasis
2-
using TensorCast
1+
import QuantumInterface: KetBraBasis, ChoiBasis
2+
#using TensorCast
33

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}
4+
const SuperOperatorType{BL,BR,T} = Operator{BL,BR,T} where {BL<:KetBraBasis,BR<:KetBraBasis}
85
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}
116

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}}
7+
#const SOpBasis = Union{KetBraBasis, PauliBasis}
8+
#const SuperOperatorType{BL,BR,T} = Operator{BL,BR,T} where {BL<:SOpBasis,BR<:SOpBasis}
9+
#const SOpKetBraType{BL,BR,T} = Operator{BL,BR,T} where {BL<:KetBraBasis,BR<:KetBraBasis}
10+
#const SOpPauliType{BL,BR,T} = Operator{BL,BR,T} where {BL<:PauliBasis,BR<:PauliBasis}
11+
#const ChoiStateType{BL,BR,T} = Operator{BL,BR,T} where {BR<:ChoiBasis,BL<:ChoiBasis}
12+
#const ChannelType = Union{SOpKetBraType, SOpPauliType, ChoiStateType, ChiType}
13+
14+
#const DenseSuperOpPureType{BL,BR} = SuperOperatorType{BL,BR,<:Matrix}
15+
#const DenseSuperOpAdjType{BL,BR} = SuperOperatorType{BL,BR,<:Adjoint{<:Number,<:Matrix}}
16+
#const DenseSuperOpType{BL,BR} = Union{DenseOpPureType{BL,BL},DenseOpAdjType{BL,BR}}
17+
#const SparseSuperOpPureType{BL,BR} = SuperOperatorType{BL,BR,<:SparseMatrixCSC}
18+
#const SparseSuperOpAdjType{BL,BR} = SuperOperatorType{BL,BR,<:Adjoint{<:Number,<:SparseMatrixCSC}}
19+
#const SparseSuperOpType{BL,BR} = Union{SparseOpPureType{BL,BR},SparseOpAdjType{BL,BR}}
1820

1921
vec(op::Operator) = Ket(KetBraBasis(basis_l(op), basis_r(op)), vec(op.data))
2022
function unvec(k::Ket{<:KetBraBasis})
@@ -43,15 +45,20 @@ sprepost(A::Operator, B::Operator) = Operator(KetBraBasis(basis_l(A), basis_r(B)
4345
# Operator(KetBraBasis(basis_l(A), basis_r(B)), KetBraBasis(basis_r(A), basis_l(B)), C)
4446
#end
4547

46-
function tensor(A::SuperOperatorType, B::SuperOperatorType)
48+
function tensor(A::T, B::T) where T<:Union{SuperOperatorType, ChoiStateType}
4749
a1, a2 = basis_l(A), basis_r(A)
4850
b1, b2 = basis_l(B), basis_r(B)
4951
#da1, da2, db1, db2 = map(dimension, (a1, a2, b1, b2))
5052
#@cast C[(ν,μ), (n,m)] |= A.data[m,μ] * B.data[n,ν] (m ∈ 1:da1, μ ∈ 1:da2, n ∈ 1:db1, ν ∈ 1:db2)
53+
#data = kron(B.data, A.data)
54+
#data = reshape(data, map(dimension, (a1, a2, b1, b2)))
55+
#data = PermutedDimsArray(data, (4, 2, 3, 1))
56+
#data = reshape(data, map(dimension, (a2⊗b2, a1⊗b1)))
57+
#return Operator(a1⊗b1, a2⊗b2, data)
5158
data = kron(B.data, A.data)
5259
data = reshape(data, map(dimension, (a1, a2, b1, b2)))
53-
data = PermutedDimsArray(data, (4, 2, 3, 1))
54-
data = reshape(data, map(dimension, (a2b2, a1b1)))
60+
data = PermutedDimsArray(data, (1, 3, 2, 4))
61+
data = reshape(data, map(dimension, (a1b1, a2b2)))
5562
return Operator(a1b1, a2b2, data)
5663
end
5764

@@ -76,31 +83,42 @@ function _super_choi(basis_fn, op)
7683
#data = _sch(op.data, l1, l2, r1, r2)
7784
#dl1, dl2, dr1, dr2 = map(dimension, (l1, l2, r1, r2))
7885
#@cast A[(ν,μ), (n,m)] |= op.data[(m,μ), (n,ν)] (m ∈ 1:dl1, μ ∈ 1:dl2, n ∈ 1:dr1, ν ∈ 1:dr2)
86+
87+
#data = reshape(op.data, map(dimension, (l1, l2, r1, r2)))
88+
#data = PermutedDimsArray(data, (4, 2, 3, 1))
89+
#data = reshape(data, map(dimension, (r2⊗l2, r1⊗l1)))
90+
#return Operator(basis_fn(r2, l2), basis_fn(r1, l1), data)
91+
7992
data = reshape(op.data, map(dimension, (l1, l2, r1, r2)))
80-
data = PermutedDimsArray(data, (4, 2, 3, 1))
81-
data = reshape(data, map(dimension, (l2r2, l1r1)))
82-
return Operator(basis_fn(r2, l2), basis_fn(r1, l1), data)
93+
data = PermutedDimsArray(data, (1, 3, 2, 4))
94+
data = reshape(data, map(dimension, (l1r1, l2r2)))
95+
return Operator(basis_fn(l1, r1), basis_fn(l2, r2), data)
8396
end
8497

8598
choi(op::SuperOperatorType) = _super_choi(ChoiBasis, op)
8699
super(op::ChoiStateType) = _super_choi(KetBraBasis, op)
100+
super(op::SuperOperatorType) = op
101+
choi(op::ChoiStateType) = op
87102

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

91106
# This method is necessary so we don't fall back to the method below it
92107
*(a::SuperOperatorType, b::SuperOperatorType) = (check_multiplicable(a,b); Operator(a.basis_l, b.basis_r, a.data*b.data))
93108
*(a::SuperOperatorType, b::Operator) = unvec(a*vec(b))
94-
*(a::ChoiStateType, b::SuperOperatorType) = super(a)*b
95-
*(a::SuperOperatorType, b::ChoiStateType) = a*super(b)
109+
96110
*(a::ChoiStateType, b::ChoiStateType) = choi(super(a)*super(b))
97111
*(a::ChoiStateType, b::Operator) = super(a)*b
98112

113+
*(a::ChoiStateType, b::SuperOperatorType) = super(a)*b
114+
*(a::SuperOperatorType, b::ChoiStateType) = a*super(b)
115+
116+
99117
identitysuperoperator(b::Basis) = Operator(KetBraBasis(b,b), KetBraBasis(b,b), Eye{ComplexF64}(dimension(b)^2))
100118

101-
identitysuperoperator(op::DenseSuperOpType) =
119+
identitysuperoperator(op::DenseOpType{BL,BR}) where {BL<:KetBraBasis, BR<:KetBraBasis} =
102120
Operator(op.basis_l, op.basis_r, Matrix(one(eltype(op.data))I, size(op.data)))
103121

104-
identitysuperoperator(op::SparseSuperOpType) =
122+
identitysuperoperator(op::SparseOpType{BL,BR}) where {BL<:KetBraBasis, BR<:KetBraBasis} =
105123
Operator(op.basis_l, op.basis_r, sparse(one(eltype(op.data))I, size(op.data)))
106124

test/runtests.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
"""
12
names = [
23
"test_states.jl",
34
@@ -60,5 +61,7 @@ for name=names
6061
include(name)
6162
end
6263
end
64+
"""
6365

66+
include("test_pauli.jl")
6467
#include("test_superoperators.jl")

0 commit comments

Comments
 (0)