Skip to content

Commit cffe1cd

Browse files
committed
TensorCast ftw
1 parent 971d9fc commit cffe1cd

File tree

3 files changed

+26
-29
lines changed

3 files changed

+26
-29
lines changed

Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
1515
RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd"
1616
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
1717
Strided = "5e0ebb24-38b0-5f93-81fe-25c709ecae67"
18+
TensorCast = "02d47bb6-7ce6-556a-be16-bb1710789e2b"
1819
UnsafeArrays = "c4a57d5a-5b31-53a6-b365-19f8c011fbd6"
1920

2021
[compat]
@@ -30,5 +31,6 @@ Random = "1"
3031
RecursiveArrayTools = "3"
3132
SparseArrays = "1"
3233
Strided = "1, 2"
34+
TensorCast = "0.4"
3335
UnsafeArrays = "1"
3436
julia = "1.10"

src/superoperators.jl

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import QuantumInterface: KetBraBasis, ChoiBasis
2+
using TensorCast
23

34
const SuperKetType = Ket{<:KetBraBasis}
45

@@ -17,45 +18,39 @@ const PauliTransferType = Operator{<:ChoiBasis,<:ChoiBasis}
1718
#const ChoiStateType = Operator{ChoiBasisType,ChoiBasisType}
1819
#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}}
1920

20-
vec(op::Operator) = Ket(KetBraBasis(basis_l(op), basis_r(op)), reshape(op.data, dimension(op.data)))
21+
vec(op::Operator) = Ket(KetBraBasis(basis_l(op), basis_r(op)), vec(op.data))
2122
function unvec(k::SuperKetType)
2223
bl, br = basis_l(basis(k)), basis_r(basis(k))
23-
return Operator(bl, br, reshape(k.data, dimension(bl), dimension(br)))
24+
@cast A[n,m] |= k.data[(n,m)] (n 1:dimension(bl), m 1:dimension(br))
25+
return Operator(bl, br, A)
2426
end
2527

2628
function spre(op::Operator)
2729
multiplicable(op, op) || throw(ArgumentError("It's not clear what spre of a non-square operator should be. See issue #113"))
28-
Operator(KetBraBasis(basis_l(op)), KetBraBasis(basis_r(op)), tensor(op, identityoperator(op)).data)
30+
sprepost(op, identityoperator(op))
2931
end
3032

3133
function spost(op::Operator)
3234
multiplicable(op, op) || throw(ArgumentError("It's not clear what spost of a non-square operator should be. See issue #113"))
33-
Operator(KetBraBasis(basis_r(op)), KetBraBasis(basis_l(op)), kron(permutedims(op.data), identityoperator(op).data))
35+
sprepost(identityoperator(op), op)
3436
end
3537

36-
sprepost(A::Operator, B::Operator) = Operator(KetBraBasis(A.basis_l, B.basis_r), KetBraBasis(A.basis_r, B.basis_l), kron(permutedims(B.data), A.data))
37-
38-
function _super_choi((l1, l2), (r1, r2), data)
39-
data = reshape(data, map(dimension, (l2, l1, r2, r1)))
40-
(l1, l2), (r1, r2) = (r2, l2), (r1, l1)
41-
data = PermutedDimsArray(data, (1, 3, 2, 4))
42-
data = reshape(data, map(dimension, (l1l2, r1r2)))
43-
return (l1, l2), (r1, r2), data
38+
function sprepost(A::Operator, B::Operator)
39+
@cast C[(ν,μ), (n,m)] |= A.data[ν,n] * B.data[m,μ]
40+
Operator(KetBraBasis(basis_l(A), basis_r(B)), KetBraBasis(basis_r(A), basis_l(B)), C)
4441
end
4542

46-
function choi(op::SuperOperatorType)
47-
bl, br = basis_l(op), basis_r(op)
48-
(l1, l2), (r1, r2) = (basis_l(bl), basis_r(bl)), (basis_l(br), basis_r(br))
49-
(l1, l2), (r1, r2), data = _super_choi((l1, l2), (r1, r2), op.data)
50-
return Operator(ChoiBasis(l1,l2), ChoiBasis(r1,r2), data)
43+
# Sec IV.A. of https://arxiv.org/abs/1111.6950
44+
function _super_choi(basis_fn, op)
45+
l1, l2 = basis_l(basis_l(op)), basis_r(basis_l(op))
46+
r1, r2 = basis_l(basis_r(op)), basis_r(basis_r(op))
47+
d1, d2, d3, d4 = map(dimension, (l1, l2, r1, r2))
48+
@cast A[(ν,μ), (n,m)] |= op.data[(m,μ), (n,ν)] (m 1:d1, μ 1:d2, n 1:d3, ν 1:d4)
49+
return Operator(basis_fn(r2, l2), basis_fn(r1, l1), A)
5150
end
5251

53-
function super(op::ChoiStateType)
54-
bl, br = basis_l(op), basis_r(op)
55-
(l1, l2), (r1, r2) = (basis_l(bl), basis_r(bl)), (basis_l(br), basis_r(br))
56-
(l1, l2), (r1, r2), data = _super_choi((l1, l2), (r1, r2), op.data)
57-
return Operator(KetBraBasis(l1,l2), KetBraBasis(r1,r2), data)
58-
end
52+
choi(op::SuperOperatorType) = _super_choi(ChoiBasis, op)
53+
super(op::ChoiStateType) = _super_choi(KetBraBasis, op)
5954

6055
dagger(a::ChoiStateType) = choi(dagger(super(a)))
6156

test/test_superoperators.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,12 @@ op2 = DenseOperator(spinbasis, [0.2+0.1im 0.1+2.3im; 0.8+4.0im 0.3+1.4im])
140140
@test tracedistance(spost(op1)*op2, op2*op1) < 1e-12
141141
@test tracedistance(choi(spost(op1))*op2, op2*op1) < 1e-12
142142

143-
@test spre(sparse(op1))*op2 == op1*op2
144-
@test choi(spre(sparse(op1)))*op2 == op1*op2
145-
@test spost(sparse(op1))*op2 == op2*op1
146-
@test choi(spost(sparse(op1)))*op2 == op2*op1
147-
@test spre(sparse(dagger(op1)))*op2 == dagger(op1)*op2
148-
@test choi(spre(sparse(dagger(op1))))*op2 == dagger(op1)*op2
143+
@test spre(sparse(op1))*op2 op1*op2
144+
@test choi(spre(sparse(op1)))*op2 op1*op2
145+
@test spost(sparse(op1))*op2 op2*op1
146+
@test choi(spost(sparse(op1)))*op2 op2*op1
147+
@test spre(sparse(dagger(op1)))*op2 dagger(op1)*op2
148+
@test choi(spre(sparse(dagger(op1))))*op2 dagger(op1)*op2
149149
@test spre(dense(dagger(op1)))*op2 dagger(op1)*op2
150150
@test choi(spre(dense(dagger(op1))))*op2 dagger(op1)*op2
151151
@test sprepost(sparse(op1), op1)*op2 op1*op2*op1

0 commit comments

Comments
 (0)