Skip to content

Commit 3f1446a

Browse files
committed
faster prepend
1 parent bd31e9b commit 3f1446a

File tree

1 file changed

+55
-8
lines changed

1 file changed

+55
-8
lines changed

src/backtrajectory.jl

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,66 @@ function expand_circuit(circuit::Vector{<:AbstractOperation})
1919
end
2020

2121

22-
# SLOW versions of prepend! and prepend_inv! for CliffordOperator
2322
"""the `prepend!` function is used to prepend any quantum operation to unitary Clifford operations"""
2423
function prepend! end
25-
function prepend!(l::CliffordOperator, r::AbstractCliffordOperator; phases=false)
26-
apply!(CliffordOperator(r, nqubits(l)), l; phases=phases)
27-
end
28-
2924
"""the prepend_inv! function is used to prepend the inverse of a quantum operation to unitary Clifford operations"""
3025
function prepend_inv! end
31-
function prepend_inv!(l::CliffordOperator, r::AbstractCliffordOperator; phases=false)
32-
apply!(inv(CliffordOperator(r, nqubits(l))), l; phases=phases)
26+
27+
# # SLOW versions of prepend! and prepend_inv! for CliffordOperator
28+
# function prepend!(l::CliffordOperator, r::AbstractCliffordOperator; phases=false)
29+
# apply!(CliffordOperator(r, nqubits(l)), l; phases=phases)
30+
# end
31+
# function prepend_inv!(l::CliffordOperator, r::AbstractCliffordOperator; phases=false)
32+
# apply!(inv(CliffordOperator(r, nqubits(l))), l; phases=phases)
33+
# end
34+
35+
36+
# FAST versions of prepend! and prepend_inv! for CliffordOperator - TODO
37+
prepend!(l::CliffordOperator, r; phases) = prepend!(l, CliffordOperator(r, nqubits(l)); phases=phases)
38+
39+
function prepend!(l::CliffordOperator, r::CliffordOperator; phases=false)
40+
nqubits(l)==nqubits(r) || throw(DimensionMismatch("The tableau and the Clifford operator need to act on the same number of qubits. Consider specifying an array of indices as a third argument to the `apply!` function to avoid this error."))
41+
l_tab = tab(l)
42+
r_tab = tab(r)
43+
threadlocal = l.buffer
44+
new_xzs = Vector{typeof(threadlocal)}(undef, length(l_tab))
45+
@inbounds for row_r in eachindex(r_tab)
46+
zero!(threadlocal)
47+
prepend_row_kernel!(threadlocal, row_r, l_tab, r_tab, phases=phases)
48+
new_xzs[row_r] = copy(threadlocal)
49+
end
50+
@inbounds for row_l in eachindex(l_tab)
51+
l_tab[row_l] = new_xzs[row_l]
52+
end
53+
l
3354
end
3455

56+
@inline function prepend_row_kernel!(new_lrow, row, l_tab, r_tab; phases=true)
57+
phases && (new_lrow.phase[] = r_tab.phases[row])
58+
n = nqubits(l_tab)
59+
for qubit in 1:n
60+
x,z = r_tab[row,qubit]
61+
if phases&&x&&z
62+
new_lrow.phase[] -= 0x1
63+
end
64+
if x
65+
mul_left!(new_lrow, l_tab, qubit, phases=Val(phases))
66+
end
67+
if z
68+
mul_left!(new_lrow, l_tab, qubit+n, phases=Val(phases))
69+
end
70+
end
71+
new_lrow
72+
end
73+
74+
function prepend_inv!(l::CliffordOperator, r::CliffordOperator; phases=false)
75+
prepend!(l, inv(r); phases=phases)
76+
end
77+
78+
# SLOW
79+
function prepend_inv!(l::CliffordOperator, r; phases=false)
80+
prepend!(l, inv(CliffordOperator(r, nqubits(l))); phases=phases)
81+
end
3582

3683
"""
3784
Simulates measurement results of a Clifford circuit acting on an `n`-qubit |0⟩^⊗n state using the stabilizer tableau backtracking method,
@@ -55,7 +102,7 @@ function backtrajectory(circuit0::Vector{<:AbstractOperation}, n::Int)
55102

56103
for op in circuit
57104
if op isa AbstractCliffordOperator
58-
T = prepend_inv!(T, op; phases=true) # VERY INEFFICIENT - need a fast prepend_inv!
105+
T = prepend_inv!(T, op; phases=true)
59106
elseif op isa sMZ
60107
pivot = 0
61108
for c in 1:n

0 commit comments

Comments
 (0)