@@ -6,7 +6,16 @@ Clifford operation or Pauli product
66julia> apply_right!(C"X Z", sHadamard(1))
77X₁ ⟼ + Z
88Z₁ ⟼ + X
9+ julia> apply_right!(C"Y Z", C"Z Y")
10+ X₁ ⟼ + Z
11+ Z₁ ⟼ - X
12+ julia> apply_right!(C"Y Z", P"X")
13+ X₁ ⟼ + Y
14+ Z₁ ⟼ - Z
15+ ```
916
17+ Example: Build a bell state decoder
18+ ```jldoctest
1019julia> cliff = one(CliffordOperator, 2)
1120X₁ ⟼ + X_
1221X₂ ⟼ + _X
@@ -22,13 +31,9 @@ X₁ ⟼ + ZX
2231X₂ ⟼ + _X
2332Z₁ ⟼ + X_
2433Z₂ ⟼ + XZ
25-
26- julia> apply_right!(C"Y Z", C"Z Y"; phases=true)
27- X₁ ⟼ + Z
28- Z₁ ⟼ - X
29- julia> apply_right!(C"Y Z", P"X")
30- X₁ ⟼ + Y
31- Z₁ ⟼ - Z
34+ julia> apply!(bell(), cliff)
35+ + Z_
36+ + _Z
3237```
3338
3439See also: [`apply!`](@ref), [`apply_inv!`](@ref)
5762function apply_right! (l:: CliffordOperator , r:: CliffordOperator ; phases= true )
5863 nqubits (l)== nqubits (r) || throw (DimensionMismatch (" The two Clifford operators need to act on the same number of qubits." ))
5964 l_tab = tab (l)
65+ l_tab_copy = copy (l_tab)
6066 r_tab = tab (r)
6167 threadlocal = l. buffer
62- new_xzs = Vector {typeof(threadlocal)} (undef, length (l_tab))
6368 @inbounds for row_r in eachindex (r_tab)
6469 zero! (threadlocal)
65- apply_right_row_kernel! (threadlocal, row_r, l_tab, r_tab, phases= phases)
66- new_xzs[row_r] = copy (threadlocal)
67- end
68- @inbounds for row_l in eachindex (l_tab)
69- l_tab[row_l] = new_xzs[row_l]
70+ apply_right_row_kernel! (threadlocal, l_tab, row_r, l_tab_copy, r_tab; phases)
7071 end
7172 l
7273end
7374
74- @inline function apply_right_row_kernel! (new_lrow, row, l_tab, r_tab; phases= true )
75+ """ helper for computing the right multiplication of a row of a Clifford operator with another Clifford operator."""
76+ @inline function apply_right_row_kernel! (new_lrow, l_tab, row, l_tab_copy, r_tab; phases= true )
7577 phases && (new_lrow. phase[] = r_tab. phases[row])
7678 n = nqubits (l_tab)
7779 for qubit in 1 : n
8082 new_lrow. phase[] -= 0x1
8183 end
8284 if x
83- mul_left! (new_lrow, l_tab , qubit, phases= Val (phases))
85+ mul_left! (new_lrow, l_tab_copy , qubit, phases= Val (phases))
8486 end
8587 if z
86- mul_left! (new_lrow, l_tab , qubit+ n, phases= Val (phases))
88+ mul_left! (new_lrow, l_tab_copy , qubit+ n, phases= Val (phases))
8789 end
8890 end
91+ l_tab[row] = new_lrow
8992 new_lrow
9093end
9194
@@ -100,13 +103,13 @@ function apply_right!(l::CliffordOperator, r::sHadamard)
100103end
101104
102105function apply_right! (l:: CliffordOperator , r:: sHadamardXY )
103- l[r . q] = mul_right_ignore_anticommute! (l[ r. q], l[ nqubits (l)+ r. q] )
106+ mul_right_ignore_anticomm! ( tab (l), r. q, nqubits (l)+ r. q)
104107 apply_right! (l, sY (r. q))
105108 return l
106109end
107110
108111function apply_right! (l:: CliffordOperator , r:: sHadamardYZ )
109- l[ nqubits (l) + r . q] = mul_right_ignore_anticommute! (l[ nqubits (l)+ r. q], l[ r. q] )
112+ mul_right_ignore_anticomm! ( tab (l), nqubits (l)+ r. q, r. q)
110113 apply_right! (l, sZ (r. q))
111114 return l
112115end
@@ -118,7 +121,7 @@ function apply_right!(l::CliffordOperator, r::sPhase)
118121end
119122
120123function apply_right! (l:: CliffordOperator , r:: sInvPhase )
121- l[r . q] = mul_right_ignore_anticommute! (l[ r. q], l[ nqubits (l)+ r. q] )
124+ mul_right_ignore_anticomm! ( tab (l), r. q, nqubits (l)+ r. q)
122125 return l
123126end
124127
@@ -145,7 +148,7 @@ function apply_right!(l::CliffordOperator, r::sSQRTX)
145148end
146149
147150function apply_right! (l:: CliffordOperator , r:: sInvSQRTX )
148- l[ nqubits (l) + r . q] = mul_right_ignore_anticommute! (l[ nqubits (l)+ r. q], l[ r. q] )
151+ mul_right_ignore_anticomm! ( tab (l), nqubits (l)+ r. q, r. q)
149152 return l
150153end
151154
@@ -163,13 +166,13 @@ end
163166
164167function apply_right! (l:: CliffordOperator , r:: sCXYZ )
165168 rowswap! (tab (l), r. q, nqubits (l)+ r. q)
166- l[r . q] = mul_right_ignore_anticommute! (l[ r. q], l[ nqubits (l)+ r. q] )
169+ mul_right_ignore_anticomm! ( tab (l), r. q, nqubits (l)+ r. q)
167170 return l
168171end
169172
170173function apply_right! (l:: CliffordOperator , r:: sCZYX )
171174 rowswap! (tab (l), r. q, nqubits (l)+ r. q)
172- l[ nqubits (l) + r . q] = mul_right_ignore_anticommute! (l[ nqubits (l)+ r. q], l[ r. q] )
175+ mul_right_ignore_anticomm! ( tab (l), nqubits (l)+ r. q, r. q)
173176 apply_right! (l, sX (r. q))
174177 return l
175178end
@@ -239,8 +242,8 @@ function apply_right!(l::CliffordOperator, r::sCPHASE)
239242end
240243
241244function apply_right! (l:: CliffordOperator , r:: sZCX )
242- l[ nqubits (l) + r . q2] = mul_right! (l[ nqubits (l)+ r. q2], l[ nqubits (l)+ r. q1]; phases = Val ( true ) )
243- l[r . q1] = mul_right! (l[ r. q1], l[ r. q2]; phases = Val ( true ) )
245+ mul_right_ignore_anticomm! ( tab (l), nqubits (l)+ r. q2, nqubits (l)+ r. q1)
246+ mul_right_ignore_anticomm! ( tab (l), r. q1, r. q2)
244247 return l
245248end
246249
@@ -252,14 +255,14 @@ function apply_right!(l::CliffordOperator, r::sZCY)
252255end
253256
254257function apply_right! (l:: CliffordOperator , r:: sZCZ )
255- l[r . q2] = mul_right! (l[ r. q2], l[ nqubits (l)+ r. q1]; phases = Val ( true ) )
256- l[r . q1] = mul_right! (l[ r. q1], l[ nqubits (l)+ r. q2]; phases = Val ( true ) )
258+ mul_right_ignore_anticomm! ( tab (l), r. q2, nqubits (l)+ r. q1)
259+ mul_right_ignore_anticomm! ( tab (l), r. q1, nqubits (l)+ r. q2)
257260 return l
258261end
259262
260263function apply_right! (l:: CliffordOperator , r:: sXCX )
261- l[ nqubits (l) + r . q2] = mul_right! (l[ nqubits (l)+ r. q2], l[ r. q1]; phases = Val ( true ) )
262- l[ nqubits (l) + r . q1] = mul_right! (l[ nqubits (l)+ r. q1], l[ r. q2]; phases = Val ( true ) )
264+ mul_right_ignore_anticomm! ( tab (l), nqubits (l)+ r. q2, r. q1)
265+ mul_right_ignore_anticomm! ( tab (l), nqubits (l)+ r. q1, r. q2)
263266 return l
264267end
265268
@@ -292,18 +295,18 @@ function apply_right!(l::CliffordOperator, r::sYCZ)
292295end
293296
294297function apply_right! (l:: CliffordOperator , r:: sZCrY )
295- l[r . q1] = mul_left! (l[ r. q1], l[ r. q2])
296- l[r . q2] = mul_left! (l[ r. q2], l[ nqubits (l)+ r. q1] )
297- l[ nqubits (l) + r . q2] = mul_left! (l[ nqubits (l)+ r. q2], l[ nqubits (l)+ r. q1] )
298- l[r . q1] = mul_left! (l[ r. q1], l[ nqubits (l)+ r. q2] )
298+ mul_right_ignore_anticomm! ( tab (l), r. q1, r. q2)
299+ mul_right_ignore_anticomm! ( tab (l), r. q2, nqubits (l)+ r. q1)
300+ mul_right_ignore_anticomm! ( tab (l), nqubits (l)+ r. q2, nqubits (l)+ r. q1)
301+ mul_right_ignore_anticomm! ( tab (l), r. q1, nqubits (l)+ r. q2)
299302 return l
300303end
301304
302305function apply_right! (l:: CliffordOperator , r:: sInvZCrY )
303- l[r . q1] = mul_left! (l[ r. q1], l[ r. q2] )
304- l[r . q2] = mul_left! (l[ r. q2], l[ nqubits (l)+ r. q1] )
305- l[ nqubits (l) + r . q2] = mul_left! (l[ nqubits (l)+ r. q2], l[ nqubits (l)+ r. q1] )
306- l[r . q1] = mul_left! (l[ r. q1], l[ nqubits (l)+ r. q2] )
306+ mul_right_ignore_anticomm! ( tab (l), r. q1, r. q2)
307+ mul_right_ignore_anticomm! ( tab (l), r. q2, nqubits (l)+ r. q1)
308+ mul_right_ignore_anticomm! ( tab (l), nqubits (l)+ r. q2, nqubits (l)+ r. q1)
309+ mul_right_ignore_anticomm! ( tab (l), r. q1, nqubits (l)+ r. q2)
307310 phases (l)[r. q1] ⊻= 0x02
308311 return l
309312end
@@ -316,10 +319,10 @@ function apply_right!(l::CliffordOperator, r::sSQRTZZ)
316319end
317320
318321function apply_right! (l:: CliffordOperator , r:: sInvSQRTZZ )
319- l[r . q1] = mul_right_ignore_anticommute! (l[ r. q1], l[ nqubits (l)+ r. q1] )
320- l[r . q1] = mul_right_ignore_anticommute! (l[ r. q1], l[ nqubits (l)+ r. q2] )
321- l[r . q2] = mul_right_ignore_anticommute! (l[ r. q2], l[ nqubits (l)+ r. q1] )
322- l[r . q2] = mul_right_ignore_anticommute! (l[ r. q2], l[ nqubits (l)+ r. q2] )
322+ mul_right_ignore_anticomm! ( tab (l), r. q1, nqubits (l)+ r. q1)
323+ mul_right_ignore_anticomm! ( tab (l), r. q1, nqubits (l)+ r. q2)
324+ mul_right_ignore_anticomm! ( tab (l), r. q2, nqubits (l)+ r. q1)
325+ mul_right_ignore_anticomm! ( tab (l), r. q2, nqubits (l)+ r. q2)
323326 return l
324327end
325328
@@ -331,10 +334,10 @@ function apply_right!(l::CliffordOperator, r::sSQRTXX)
331334end
332335
333336function apply_right! (l:: CliffordOperator , r:: sInvSQRTXX )
334- l[ nqubits (l) + r . q1] = mul_right_ignore_anticommute! (l[ nqubits (l)+ r. q1], l[ r. q1] )
335- l[ nqubits (l) + r . q1] = mul_right_ignore_anticommute! (l[ nqubits (l)+ r. q1], l[ r. q2] )
336- l[ nqubits (l) + r . q2] = mul_right_ignore_anticommute! (l[ nqubits (l)+ r. q2], l[ r. q1] )
337- l[ nqubits (l) + r . q2] = mul_right_ignore_anticommute! (l[ nqubits (l)+ r. q2], l[ r. q2])
337+ mul_right_ignore_anticomm! ( tab (l), nqubits (l)+ r. q1, r. q1)
338+ mul_right_ignore_anticomm! ( tab (l), nqubits (l)+ r. q1, r. q2)
339+ mul_right_ignore_anticomm! ( tab (l), nqubits (l)+ r. q2, r. q1)
340+ mul_right_ignore_anticomm! ( tab (l), nqubits (l)+ r. q2, r. q2)
338341 return l
339342end
340343
@@ -346,12 +349,12 @@ function apply_right!(l::CliffordOperator, r::sSQRTYY)
346349end
347350
348351function apply_right! (l:: CliffordOperator , r:: sInvSQRTYY )
349- l[r . q1] = mul_right_ignore_anticommute! (l[ r. q1], l[ nqubits (l)+ r. q1] )
350- l[ nqubits (l) + r . q1] = mul_right_ignore_anticommute! (l[ nqubits (l)+ r. q1], l[ nqubits (l)+ r. q2] )
351- l[ nqubits (l) + r . q1] = mul_right_ignore_anticommute! (l[ nqubits (l)+ r. q1], l[ r. q2] )
352- l[r . q2] = mul_right_ignore_anticommute! (l[ r. q2], l[ r. q1] )
353- l[ nqubits (l) + r . q2] = mul_right_ignore_anticommute! (l[ nqubits (l)+ r. q2], l[ r. q1] )
354- l[r . q1] = mul_right_ignore_anticommute! (l[ r. q1], l[ nqubits (l)+ r. q1])
352+ mul_right_ignore_anticomm! ( tab (l), r. q1, nqubits (l)+ r. q1)
353+ mul_right_ignore_anticomm! ( tab (l), nqubits (l)+ r. q1, nqubits (l)+ r. q2)
354+ mul_right_ignore_anticomm! ( tab (l), nqubits (l)+ r. q1, r. q2)
355+ mul_right_ignore_anticomm! ( tab (l), r. q2, r. q1)
356+ mul_right_ignore_anticomm! ( tab (l), nqubits (l)+ r. q2, r. q1)
357+ mul_right_ignore_anticomm! ( tab (l), r. q1, nqubits (l)+ r. q1)
355358 rowswap! (tab (l), r. q1, nqubits (l)+ r. q1)
356359 rowswap! (tab (l), r. q2, nqubits (l)+ r. q2)
357360 apply_right! (l, sZ (r. q2))
361364
362365""" Multiply Pauli operators `l * r`, ignoring anticommutation phases (keeping only ±1, not ±i).
363366See also: [`mul_right!`](@ref)."""
364- function mul_right_ignore_anticommute! (l:: PauliOperator , r:: PauliOperator )
365- mul_right! (l, r; phases= Val (true ))
366- l. phase[] = l. phase[] & 0x02
367- return l
367+ @inline function mul_right_ignore_anticomm! (s:: Tableau , m, t:: Tableau , i; phases:: Val{B} = Val (true )) where B
368+ extra_phase = mul_right! ((@view s. xzs[:,m]), (@view t. xzs[:,i]); phases= phases)
369+ B && (s. phases[m] = (extra_phase+ s. phases[m]+ s. phases[i])& 0x2 )
370+ s
371+ end
372+ @inline function mul_right_ignore_anticomm! (s:: Tableau , m, i; phases:: Val{B} = Val (true )) where B
373+ extra_phase = mul_right! ((@view s. xzs[:,m]), (@view s. xzs[:,i]); phases= phases)
374+ B && (s. phases[m] = (extra_phase+ s. phases[m]+ s. phases[i])& 0x2 )
375+ s
368376end
0 commit comments