Skip to content

Commit fecd7cf

Browse files
committed
More WIP Pauli
1 parent 0095240 commit fecd7cf

File tree

4 files changed

+84
-88
lines changed

4 files changed

+84
-88
lines changed

src/QuantumOpticsBase.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import QuantumInterface: Basis, GenericBasis, CompositeBasis, basis, basis_l, ba
88
IncompatibleBases, @compatiblebases, samebases, check_samebases,
99
addible, check_addible, multiplicable, check_multiplicable, reduced, ptrace, permutesystems,
1010
dagger, directsum, , dm, embed, expect, identityoperator, identitysuperoperator,
11-
permutesystems, projector, ptrace, reduced, tensor, , variance, apply!,
11+
permutesystems, projector, ptrace, reduced, tensor, tensor_pow, , variance, apply!,
1212
vec, unvec, super, choi, kraus, stinespring, pauli, chi, spre, spost, sprepost, liouvillian
1313

1414
# metrics
@@ -18,7 +18,7 @@ import QuantumInterface: entropy_vn, fidelity, logarithmic_negativity
1818
import QuantumInterface: complement, remove, shiftremove, reducedindices!, check_indices, check_sortedindices, check_embed_indices
1919

2020
export Basis, GenericBasis, CompositeBasis, basis, basis_l, basis_r, dimension, shape,
21-
tensor, , permutesystems, @compatiblebases,
21+
tensor, tensor_pow, , permutesystems, @compatiblebases,
2222
#states
2323
StateVector, Bra, Ket, basisstate, sparsebasisstate, norm,
2424
dagger, normalize, normalize!,
@@ -98,7 +98,7 @@ include("particle.jl")
9898
include("nlevel.jl")
9999
include("manybody.jl")
100100
include("transformations.jl")
101-
#include("pauli.jl")
101+
include("pauli.jl")
102102
include("metrics.jl")
103103
include("spinors.jl")
104104
include("phasespace.jl")

src/pauli.jl

Lines changed: 31 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,55 @@
1-
using TransmuteDims
21

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
23-
24-
function _pauli_to_comp1()
2+
# comp stands for computational basis
3+
function _comp_pauli_1(basis_fn)
254
b = SpinBasis(1//2)
26-
vec_it(fn) = vec(fn(b).data)
5+
vec_it(fn) = vec(fn(b).data)/2 # provides "standard" normalization
276
V = hcat(map(vec_it, [identityoperator, sigmax, sigmay, sigmaz])...)
28-
Operator(PauliBasis(), KetBraBasis(b, b), V)
7+
Operator(basis_fn(b, b), PauliBasis(1), V)
298
end
309

31-
_pauli_to_comp1_cached = _pauli_to_comp1()
10+
_comp_pauli_kb1_cached = _comp_pauli_1(KetBraBasis)
11+
_comp_pauli_choi1_cached = _comp_pauli_1(ChoiBasis)
3212

33-
# TODO should this be further cached?
13+
# TODO: should this be further cached?
3414
"""
35-
comp_to_pauli(N)
15+
pauli_comp_kb(N)
3616
37-
Creates a superoperator which changes from the computational `SpinBasis(1//2)`
17+
Creates a superoperator which changes from the computational `KetBra(SpinBasis(1//2))`
3818
to the `PauliBasis()` over `N` qubits.
3919
"""
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)
46-
end
20+
comp_pauli_kb(N::Integer) = tensor_pow(_comp_pauli_kb1_cached, N)
21+
comp_pauli_choi(N::Integer) = tensor_pow(_comp_pauli_choi1_cached, N)
4722

4823
function _check_is_spinbasis(b)
4924
for i=1:length(b)
5025
(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"))
5126
end
5227
end
5328

29+
# It's possible to get better asympotic speedups using, e.g. methods from
30+
# https://iopscience.iop.org/article/10.1088/1402-4896/ad6499
31+
# https://arxiv.org/abs/2411.00526
32+
# https://quantum-journal.org/papers/q-2024-09-05-1461/ (see appendices)
33+
function pauli(op::Operator)
34+
(basis_l(op) == basis_r(op)) || throw(ArgumentError("Operator must be square in order to be vectorized to the pauli represenation"))
35+
_check_is_spinbasis(basis_l(op))
36+
dagger(comp_pauli_kb(length(basis_l(op)))) * vec(op)
37+
end
38+
5439
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))
40+
bl, br = basis_l(op), basis_r(op)
41+
((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"))
42+
bl, br = basis_l(bl), basis_l(br)
5743
foreach(_check_is_spinbasis, (bl, br))
5844

59-
Nl, Nr = length(basis_l(bl)), length(basis_l(br))
60-
Vl = pauli_to_comp(Nl)
61-
Vr = Nl == Nr ? Vl : pauli_to_comp(Nr)
45+
Nl, Nr = length(bl), length(br)
46+
Vl = comp_pauli_kb(Nl)
47+
Vr = Nl == Nr ? Vl : comp_pauli_kb(Nr)
6248
#data = dagger(Ul)*op.data*Ur # TODO figure out normalization
6349
#@assert isapprox(imag.(data), zero(data), atol=tol)
6450
#Operator(PauliBasis()^Nl, PauliBasis()^Nr, real.(data))
6551
dagger(Vl) * op * Vr # TODO figure out normalization
52+
# TODO make sure dagger here is okay...
6653
end
6754

6855
function chi(op::ChoiStateType)
@@ -71,11 +58,9 @@ function chi(op::ChoiStateType)
7158
foreach(_check_is_spinbasis, (bl, br))
7259

7360
Nl, Nr = length(bl), length(br)
74-
Ul = ket_bra_to_pauli(Nl)
75-
Ur = Nl == Nr ? Ul : ket_bra_to_pauli(Nr)
76-
data = dagger(Ul)*op.data*Ur # TODO figure out normalization
77-
@assert isapprox(imag.(data), zero(data), atol=tol)
78-
Operator(PauliBasis()^Nl, PauliBasis()^Nr, real.(data))
61+
Vl = comp_pauli_kb(Nl)
62+
Vr = Nl == Nr ? Vl : comp_pauli_kb(Nr)
63+
dagger(Vl) * op * Vr # TODO figure out normalization
7964
end
8065

8166
"""

src/superoperators.jl

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@ const SparseSuperOpAdjType{BL,BR} = SuperOperatorType{BL,BR,<:Adjoint{<:Number,<
1717
const SparseSuperOpType{BL,BR} = Union{SparseOpPureType{BL,BR},SparseOpAdjType{BL,BR}}
1818

1919
vec(op::Operator) = Ket(KetBraBasis(basis_l(op), basis_r(op)), vec(op.data))
20-
#function unvec(k::Ket{<:KetBraBasis})
21-
# bl, br = basis_l(basis(k)), basis_r(basis(k))
22-
# Operator(bl, br, reshape(k.data, dimension(bl), dimension(br)))
23-
#end
2420
function unvec(k::Ket{<:KetBraBasis})
2521
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)
22+
Operator(bl, br, reshape(k.data, dimension(bl), dimension(br)))
2823
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
2929

3030
function spre(op::Operator)
3131
multiplicable(op, op) || throw(ArgumentError("It's not clear what spre of a non-square operator should be. See issue #113"))
@@ -37,18 +37,22 @@ function spost(op::Operator)
3737
sprepost(identityoperator(op), op)
3838
end
3939

40-
#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))
41-
function sprepost(A::Operator, B::Operator)
42-
@cast C[(ν,μ), (n,m)] |= A.data[ν,n] * B.data[m,μ]
43-
Operator(KetBraBasis(basis_l(A), basis_r(B)), KetBraBasis(basis_r(A), basis_l(B)), C)
44-
end
40+
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))
41+
#function sprepost(A::Operator, B::Operator)
42+
# @cast C[(ν,μ), (n,m)] |= A.data[ν,n] * B.data[m,μ]
43+
# Operator(KetBraBasis(basis_l(A), basis_r(B)), KetBraBasis(basis_r(A), basis_l(B)), C)
44+
#end
4545

4646
function tensor(A::SuperOperatorType, B::SuperOperatorType)
4747
a1, a2 = basis_l(A), basis_r(A)
4848
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)
49+
#da1, da2, db1, db2 = map(dimension, (a1, a2, b1, b2))
50+
#@cast C[(ν,μ), (n,m)] |= A.data[m,μ] * B.data[n,ν] (m ∈ 1:da1, μ ∈ 1:da2, n ∈ 1:db1, ν ∈ 1:db2)
51+
data = kron(B.data, A.data)
52+
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)))
55+
return Operator(a1b1, a2b2, data)
5256
end
5357

5458
#function _sch(data, l1, l2, r1, r2)
@@ -79,13 +83,13 @@ end
7983
function _super_choi(basis_fn, op)
8084
l1, l2 = basis_l(basis_l(op)), basis_r(basis_l(op))
8185
r1, r2 = basis_l(basis_r(op)), basis_r(basis_r(op))
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)
88-
return Operator(basis_fn(r2, l2), basis_fn(r1, l1), A)
86+
#data = _sch(op.data, l1, l2, r1, r2)
87+
#dl1, dl2, dr1, dr2 = map(dimension, (l1, l2, r1, r2))
88+
#@cast A[(ν,μ), (n,m)] |= op.data[(m,μ), (n,ν)] (m ∈ 1:dl1, μ ∈ 1:dl2, n ∈ 1:dr1, ν ∈ 1:dr2)
89+
data = reshape(op.data, map(dimension, (l1, l2, r1, r2)))
90+
data = PermutedDimsArray(data, (4, 2, 3, 1))
91+
data = reshape(data, map(dimension, (l2r2, l1r1)))
92+
return Operator(basis_fn(r2, l2), basis_fn(r1, l1), data)
8993
end
9094

9195
choi(op::SuperOperatorType) = _super_choi(ChoiBasis, op)

test/test_pauli.jl

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,48 @@ using LinearAlgebra
22
using Test
33

44
using QuantumOpticsBase
5+
import QuantumOpticsBase: comp_pauli_kb
56

67
@testset "pauli" begin
78

89
b = SpinBasis(1//2)
10+
Isop = sprepost(identityoperator(b), dagger(identityoperator(b)))
11+
Xsop = sprepost(sigmax(b), dagger(sigmax(b)))
12+
Ysop = sprepost(sigmay(b), dagger(sigmay(b)))
13+
Zsop = sprepost(sigmaz(b), dagger(sigmaz(b)))
14+
Xsk = vec(sigmax(b))
15+
V = comp_pauli_kb(1)
16+
17+
918
# Test conversion of unitary matrices to superoperators.
10-
q2 = b^2
11-
q3 = b^3
12-
CZ = DenseOperator(q2, q2, diagm(0 => [1,1,1,-1]))
13-
CZ_sop = SuperOperator(CZ)
19+
CZ = dm(spinup(b))identityoperator(b) + dm(spindown(b))sigmaz(b)
20+
CZ_sop = sprepost(CZ,dagger(CZ))
1421

1522
# Test conversion of unitary matrices to superoperators.
1623
@test diag(CZ_sop.data) == ComplexF64[1,1,1,-1,1,1,1,-1,1,1,1,-1,-1,-1,-1,1]
17-
@test CZ_sop.basis_l == CZ_sop.basis_r == (q2, q2)
24+
@test basis_l(CZ_sop) == basis_r(CZ_sop) == KetBraBasis(b^2, b^2)
1825

1926
# Test conversion of superoperator to Pauli transfer matrix.
20-
CZ_ptm = PauliTransferMatrix(CZ_sop)
27+
CZ_ptm = pauli(CZ_sop)
2128

2229
# Test DensePauliTransferMatrix constructor.
23-
@test_throws DimensionMismatch DensePauliTransferMatrix((q2, q2), (q3, q3), CZ_ptm.data)
24-
@test DensePauliTransferMatrix((q2, q2), (q2, q2), CZ_ptm.data) == CZ_ptm
30+
@test_throws DimensionMismatch Operator(PauliBasis(2), PauliBasis(3), CZ_ptm.data)
31+
@test Operator(PauliBasis(2), PauliBasis(2), CZ_ptm.data) == CZ_ptm
2532

26-
@test all(isapprox.(CZ_ptm.data[[1,30,47,52,72,91,117,140,166,185,205,210,227,256]], 1))
27-
@test all(isapprox.(CZ_ptm.data[[106,151]], -1))
33+
@test all(isapprox.(CZ_ptm.data[[1,30,47,52,72,91,117,140,166,185,205,210,227,256]], 4))
34+
@test all(isapprox.(CZ_ptm.data[[106,151]], -4))
2835

2936
@test CZ_ptm == PauliTransferMatrix(ChiMatrix(CZ))
3037

3138
# Test construction of non-symmetric unitary.
32-
CNOT = DenseOperator(q2, q2, diagm(0 => [1,1,0,0], 1 => [0,0,1], -1 => [0,0,1]))
39+
CNOT = DenseOperator(b^2, b^2, diagm(0 => [1,1,0,0], 1 => [0,0,1], -1 => [0,0,1]))
3340
CNOT_sop = SuperOperator(CNOT)
3441
CNOT_chi = ChiMatrix(CNOT)
3542
CNOT_ptm = PauliTransferMatrix(CNOT)
3643

37-
@test CNOT_sop.basis_l == CNOT_sop.basis_r == (q2, q2)
38-
@test CNOT_chi.basis_l == CNOT_chi.basis_r == (q2, q2)
39-
@test CNOT_ptm.basis_l == CNOT_ptm.basis_r == (q2, q2)
44+
@test CNOT_sop.basis_l == CNOT_sop.basis_r == (b^2, b^2)
45+
@test CNOT_chi.basis_l == CNOT_chi.basis_r == (b^2, b^2)
46+
@test CNOT_ptm.basis_l == CNOT_ptm.basis_r == (b^2, b^2)
4047

4148
@test all(isapprox.(imag.(CNOT_sop.data), 0))
4249
@test all(isapprox.(imag.(CNOT_chi.data), 0))
@@ -49,13 +56,13 @@ CNOT_ptm = PauliTransferMatrix(CNOT)
4956
@test all(isapprox.(CNOT_ptm.data[[123,168]], -1))
5057

5158
# Test DenseChiMatrix constructor.
52-
@test_throws DimensionMismatch DenseChiMatrix((q2, q2), (q3, q3), CNOT_chi.data)
53-
@test DenseChiMatrix((q2, q2), (q2, q2), CNOT_chi.data) == CNOT_chi
59+
@test_throws DimensionMismatch Operator(ChoiBasis(PauliBasis(2), PauliBasis(2)), ChoiBasis(PauliBasis(3), PauliBasis(3)), CNOT_chi.data)
60+
@test Operator(ChoiBasis(PauliBasis(2), PauliBasis(2)), CNOT_chi.data) == CNOT_chi
5461

5562
# Test equality and conversion among all three bases.
5663
ident = Complex{Float64}[1 0 0 0; 0 1 0 0; 0 0 1 0; 0 0 0 1]
5764

58-
IDENT = DenseOperator(q2, ident)
65+
IDENT = DenseOperator(b^2, ident)
5966

6067
IDENT_sop = SuperOperator(IDENT)
6168
IDENT_chi = ChiMatrix(IDENT)
@@ -71,7 +78,7 @@ IDENT_ptm = PauliTransferMatrix(IDENT)
7178
# Test approximate equality and conversion among all three bases.
7279
cphase = Complex{Float64}[1 0 0 0; 0 1 0 0; 0 0 1 0; 0 0 0 exp(1im*.6)]
7380

74-
CPHASE = DenseOperator(q2, cphase)
81+
CPHASE = DenseOperator(b^2, cphase)
7582

7683
CPHASE_sop = SuperOperator(CPHASE)
7784
CPHASE_chi = ChiMatrix(CPHASE)

0 commit comments

Comments
 (0)