Skip to content

Commit 3c8e541

Browse files
apply_inv! (#501)
Co-authored-by: Stefan Krastanov <[email protected]> Co-authored-by: Stefan Krastanov <[email protected]>
1 parent b10feda commit 3c8e541

File tree

6 files changed

+163
-48
lines changed

6 files changed

+163
-48
lines changed

.typos.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
ket = "ket"
33
anc = "anc"
44
ba = "ba"
5+
IY = "IY"
56
mor = "mor"
67

78
[type.ipynb]

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
## v0.10.1-dev
99

10+
- Implementing `apply_inv!` for direct application of the inverse of a given gate.
1011
- The lifted product code constructor `LPCode` now supports non-commutative group algebras by appropriate switching left/right representations — particularly useful now that there is also an `Oscar` extension, which provides many non-abelian group constructors.
1112
- Introduce `metacheck_matrix_x`, `metacheck_matrix_z`, and `metacheck_matrix` for CSS codes built using chain complexes and homology.
1213
- `ReedMuller`, `RecursiveReedMuller`, and `QuantumReedMuller` are moved to `QECCore` from `QuantumClifford.ECC`.

src/QuantumClifford.jl

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export
4040
# Linear Algebra
4141
tensor, tensor_pow,
4242
logdot, expect,
43-
apply!,
43+
apply!, apply_inv!,
4444
permutesystems, permutesystems!,
4545
# Low Level Function Interface
4646
generate!, project!, reset_qubits!, traceout!,
@@ -1076,9 +1076,12 @@ Base.hcat(stabs::Stabilizer{T}...) where {T} = Stabilizer(hcat((tab(s) for s in
10761076
# Unitary Clifford Operations
10771077
##############################
10781078

1079-
"""In `QuantumClifford` the `apply!` function is used to apply any quantum operation to a stabilizer state,
1080-
including unitary Clifford operations, Pauli measurements, and noise.
1081-
Thus, this function may result in a random/stochastic result (e.g. with measurements or noise)."""
1079+
"""
1080+
apply!
1081+
1082+
Apply any quantum operation to a stabilizer state, including unitary Clifford
1083+
operations, Pauli measurements, and noise.
1084+
May result in a random/stochastic result (e.g. with measurements or noise)."""
10821085
function apply! end
10831086

10841087
function Base.:(*)(p::AbstractCliffordOperator, s::AbstractStabilizer; phases::Bool=true)
@@ -1117,6 +1120,28 @@ function _apply!(stab::AbstractStabilizer, p::PauliOperator, indices; phases::Va
11171120
stab
11181121
end
11191122

1123+
1124+
"""
1125+
apply_inv!
1126+
1127+
Apply the inverse of any quantum operation to a stabilizer state.
1128+
"""
1129+
function apply_inv! end
1130+
1131+
function apply_inv!(stab::AbstractStabilizer, op::AbstractCliffordOperator; phases::Bool=true)
1132+
@valbooldispatch _apply_inv!(stab,op; phases=Val(phases)) phases
1133+
end
1134+
function apply_inv!(stab::AbstractStabilizer, op::AbstractCliffordOperator, indices; phases::Bool=true)
1135+
@valbooldispatch _apply_inv!(stab,op,indices; phases=Val(phases)) phases
1136+
end
1137+
1138+
function _apply_inv!(stab::AbstractStabilizer, p::PauliOperator; phases::Val{B}=Val(true)) where B
1139+
apply!(stab,p; phases=phases)
1140+
end
1141+
function _apply_inv!(stab::AbstractStabilizer, p::PauliOperator, indices; phases::Val{B}=Val(true)) where B
1142+
apply!(stab,p,indices; phases=phases)
1143+
end
1144+
11201145
##############################
11211146
# Conversion and promotion
11221147
##############################

src/dense_cliffords.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ function apply!(r::CliffordOperator, l::AbstractCliffordOperator; phases=false)
106106
r
107107
end
108108

109+
function apply_inv!(r::CliffordOperator, l::AbstractCliffordOperator; phases=false)
110+
@valbooldispatch _apply_inv!(Stabilizer(tab(r)),l,phases=Val(phases)) phases
111+
r
112+
end
113+
109114
"""Nonvectorized version of `apply!` used for unit tests."""
110115
function _apply_nonthread!(stab::AbstractStabilizer, c::CliffordOperator; phases::Bool=true)
111116
nqubits(stab)==nqubits(c) || 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."))
@@ -132,6 +137,10 @@ function _apply!(stab::AbstractStabilizer, c::CliffordOperator; phases::Val{B}=V
132137
stab
133138
end
134139

140+
function _apply_inv!(stab::AbstractStabilizer, c::CliffordOperator; phases::Val{B}=Val(true)) where B
141+
_apply!(stab, inv(c); phases=phases)
142+
end
143+
135144
# TODO Added a lot of type assertions to help Julia infer types, but they are much too strict for cases where bitpacking varies (check tests)
136145
@inline function apply_row_kernel!(new_stabrow, row, s_tab, c_tab; phases::Val{B}=Val(true)) where B
137146
B && (new_stabrow.phase[] = s_tab.phases[row])
@@ -177,6 +186,10 @@ function _apply!(stab::AbstractStabilizer, c::CliffordOperator, indices_of_appli
177186
stab
178187
end
179188

189+
function _apply_inv!(stab::AbstractStabilizer, c::CliffordOperator, indices_of_application::AbstractArray{Int,1}; phases::Val{B}=Val(true)) where B
190+
_apply!(stab, inv(c), indices_of_application; phases=phases)
191+
end
192+
180193
@inline function apply_row_kernel!(new_stabrow, row, s_tab, c_tab, indices_of_application; phases::Val{B}=Val(true)) where B
181194
B && (new_stabrow.phase[] = s_tab.phases[row])
182195
n = nqubits(c_tab)

src/symbolic_cliffords.jl

Lines changed: 88 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ Base.@propagate_inbounds setzbit(xzs::AbstractMatrix{T}, r::Int, c::Int, z::T, s
5757
# Single-qubit gates
5858
##############################
5959

60-
function _apply!(stab::AbstractStabilizer, gate::G; phases::Val{B}=Val(true)) where {B, G<:AbstractSingleQubitOperator}
60+
function _apply!(stab::AbstractStabilizer, gate::AbstractSingleQubitOperator; phases::Val{B}=Val(true)) where {B}
6161
s = tab(stab)
6262
c = gate.q
6363
@inbounds @simd for r in eachindex(s)
@@ -71,8 +71,22 @@ function _apply!(stab::AbstractStabilizer, gate::G; phases::Val{B}=Val(true)) wh
7171
stab
7272
end
7373

74+
function _apply_inv!(stab::AbstractStabilizer, gate::AbstractSingleQubitOperator; phases::Val{B}=Val(true)) where {B} # code repetition with the corresponding `_apply`
75+
s = tab(stab)
76+
c = gate.q
77+
@inbounds @simd for r in eachindex(s)
78+
x = getxbit(s, r, c)
79+
z = getzbit(s, r, c)
80+
x,z,phase = inv_qubit_kernel(gate,x,z)
81+
setxbit(s, r, c, x)
82+
setzbit(s, r, c, z)
83+
B && phase && (s.phases[r] = (s.phases[r]+0x2)&3)
84+
end
85+
stab
86+
end
87+
7488
"""Macro used to define single qubit symbolic gates and their `qubit_kernel` methods."""
75-
macro qubitop1(name, kernel)
89+
macro qubitop1(name, kernel, inv_kernel)
7690
prefixname = Symbol(:s,name)
7791
docstring = "A \"symbolic\" single-qubit $name. See also: [`SingleQubitOperator`](@ref), [`AbstractSymbolicOperator`](@ref)"
7892
quote
@@ -82,23 +96,24 @@ macro qubitop1(name, kernel)
8296
end
8397
@doc $docstring $prefixname
8498
@inline $(esc(:qubit_kernel))(::$prefixname, x, z) = $kernel
99+
@inline $(esc(:inv_qubit_kernel))(::$prefixname, x, z) = $inv_kernel
85100
end
86101
end
87102

88-
@qubitop1 Hadamard (z ,x , x!=0 && z!=0)
89-
@qubitop1 HadamardXY (x ,xz , x==0 && z!=0)
90-
@qubitop1 HadamardYZ (xz ,z , x!=0 && z==0)
91-
@qubitop1 Phase (x ,xz , x!=0 && z!=0)
92-
@qubitop1 InvPhase (x ,xz , x!=0 && z==0)
93-
@qubitop1 X (x ,z , z!=0)
94-
@qubitop1 Y (x ,z , (xz)!=0)
95-
@qubitop1 Z (x ,z , x!=0)
96-
@qubitop1 SQRTX (xz ,z , x==0 && z!=0)
97-
@qubitop1 InvSQRTX (xz ,z , x!=0 && z!=0)
98-
@qubitop1 SQRTY (z ,x , x!=0 && z==0)
99-
@qubitop1 InvSQRTY (z ,x , z!=0 && x==0)
100-
@qubitop1 CXYZ (xz ,x , false)
101-
@qubitop1 CZYX (z ,xz , false)
103+
@qubitop1 Hadamard (z ,x , x!=0 && z!=0) (z ,x , x!=0 && z!=0)
104+
@qubitop1 HadamardXY (x ,xz , x==0 && z!=0) (x ,xz , x==0 && z!=0)
105+
@qubitop1 HadamardYZ (xz ,z , x!=0 && z==0) (xz ,z , x!=0 && z==0)
106+
@qubitop1 Phase (x ,xz , x!=0 && z!=0) (x ,xz , x!=0 && z==0)
107+
@qubitop1 InvPhase (x ,xz , x!=0 && z==0) (x ,xz , x!=0 && z!=0)
108+
@qubitop1 X (x ,z , z!=0) (x ,z , z!=0)
109+
@qubitop1 Y (x ,z , (xz)!=0) (x ,z , (xz)!=0)
110+
@qubitop1 Z (x ,z , x!=0) (x ,z , x!=0)
111+
@qubitop1 SQRTX (xz ,z , x==0 && z!=0) (xz ,z , x!=0 && z!=0)
112+
@qubitop1 InvSQRTX (xz ,z , x!=0 && z!=0) (xz ,z , x==0 && z!=0)
113+
@qubitop1 SQRTY (z ,x , x!=0 && z==0) (z ,x , z!=0 && x==0)
114+
@qubitop1 InvSQRTY (z ,x , z!=0 && x==0) (z ,x , x!=0 && z==0)
115+
@qubitop1 CXYZ (xz ,x , false) (z ,xz , false)
116+
@qubitop1 CZYX (z ,xz , false) (xz ,x , false)
102117

103118
"""A "symbolic" single-qubit Identity operation.
104119
@@ -111,6 +126,9 @@ end
111126
function _apply!(stab::AbstractStabilizer, ::sId1; phases::Val{B}=Val(true)) where B
112127
stab
113128
end
129+
function _apply_inv!(stab::AbstractStabilizer, ::sId1; phases::Val{B}=Val(true)) where B
130+
stab
131+
end
114132

115133
"""A "symbolic" general single-qubit operator which permits faster multiplication than an operator expressed as an explicit tableau.
116134
@@ -270,7 +288,7 @@ LinearAlgebra.inv(p::sCXYZ) = sCZYX(p.q)
270288
# Two-qubit gates
271289
##############################
272290

273-
function _apply!(stab::AbstractStabilizer, gate::G; phases::Val{B}=Val(true)) where {B, G<:AbstractTwoQubitOperator}
291+
function _apply!(stab::AbstractStabilizer, gate::AbstractTwoQubitOperator; phases::Val{B}=Val(true)) where {B}
274292
s = tab(stab)
275293
q1 = gate.q1
276294
q2 = gate.q2
@@ -295,8 +313,33 @@ function _apply!(stab::AbstractStabilizer, gate::G; phases::Val{B}=Val(true)) wh
295313
stab
296314
end
297315

316+
function _apply_inv!(stab::AbstractStabilizer, gate::AbstractTwoQubitOperator; phases::Val{B}=Val(true)) where {B} # code repetition with the corresponding `_apply`
317+
s = tab(stab)
318+
q1 = gate.q1
319+
q2 = gate.q2
320+
Tₘₑ = eltype(s.xzs)
321+
shift = getshift(Tₘₑ, q1) - getshift(Tₘₑ, q2)
322+
@inbounds @simd for r in eachindex(s)
323+
# for r in eachindex(s)
324+
x1 = getxbit(s, r, q1)
325+
z1 = getzbit(s, r, q1)
326+
x2 = getxbit(s, r, q2)<<shift
327+
z2 = getzbit(s, r, q2)<<shift
328+
x1,z1,x2,z2,phase = inv_qubit_kernel(gate,x1,z1,x2,z2) # Most `inv_qubit_kernel` functions are defined by a `qubitop2` macro
329+
setxbit(s, r, q1, x1, 0)
330+
setzbit(s, r, q1, z1, 0)
331+
setxbit(s, r, q2, x2, -shift)
332+
setzbit(s, r, q2, z2, -shift)
333+
if B && phase
334+
s.phases[r] += 0x2
335+
s.phases[r] &= 3
336+
end
337+
end
338+
stab
339+
end
340+
298341
"""Macro used to define 2-qubit symbolic gates and their `qubit_kernel` methods."""
299-
macro qubitop2(name, kernel)
342+
macro qubitop2(name, kernel, inv_kernel)
300343
prefixname = Symbol(:s,name)
301344
docstring = "A \"symbolic\" $name. See also: [`AbstractSymbolicOperator`](@ref)"
302345
quote
@@ -307,46 +350,47 @@ macro qubitop2(name, kernel)
307350
end
308351
@doc $docstring $prefixname
309352
@inline $(esc(:qubit_kernel))(::$prefixname, x1, z1, x2, z2) = $kernel
353+
@inline $(esc(:inv_qubit_kernel))(::$prefixname, x1, z1, x2, z2) = $inv_kernel
310354
end
311355
end
312356
# x1 z1 x2 z2
313-
@qubitop2 SWAP (x2 , z2 , x1 , z1 , false)
357+
@qubitop2 SWAP (x2 , z2 , x1 , z1 , false) (x2 , z2 , x1 , z1 , false)
314358

315-
@qubitop2 SWAPCX (x2 , z2z1 , x2x1 , z1 , ~iszero((x1 & z1 & x2 & z2) | (~x1 & z1 & x2 & ~z2)))
316-
@qubitop2 InvSWAPCX (x2x1 , z2 , x1 , z2z1 , ~iszero((x1 & z1 & x2 & z2) | ( x1 &~z1 &~x2 & z2)))
359+
@qubitop2 SWAPCX (x2 , z2z1 , x2x1 , z1 , ~iszero((x1 & z1 & x2 & z2) | (~x1 & z1 & x2 & ~z2))) (x2x1 , z2 , x1 , z2z1 , ~iszero((x1 & z1 & x2 & z2) | ( x1 &~z1 &~x2 & z2)))
360+
@qubitop2 InvSWAPCX (x2x1 , z2 , x1 , z2z1 , ~iszero((x1 & z1 & x2 & z2) | ( x1 &~z1 &~x2 & z2))) (x2 , z2z1 , x2x1 , z1 , ~iszero((x1 & z1 & x2 & z2) | (~x1 & z1 & x2 & ~z2)))
317361

318-
@qubitop2 ISWAP (x2 , x1z2x2 , x1 , x1x2z1 , ~iszero((x1 & z1 & ~x2) | (~x1 & x2 & z2)))
319-
@qubitop2 InvISWAP (x2 , x1z2x2 , x1 , x1x2z1 , ~iszero((x1 &~z1 & ~x2) | (~x1 & x2 &~z2)))
362+
@qubitop2 ISWAP (x2 , x1z2x2 , x1 , x1x2z1 , ~iszero((x1 & z1 & ~x2) | (~x1 & x2 & z2))) (x2 , x1z2x2 , x1 , x1x2z1 , ~iszero((x1 &~z1 & ~x2) | (~x1 & x2 &~z2)))
363+
@qubitop2 InvISWAP (x2 , x1z2x2 , x1 , x1x2z1 , ~iszero((x1 &~z1 & ~x2) | (~x1 & x2 &~z2))) (x2 , x1z2x2 , x1 , x1x2z1 , ~iszero((x1 & z1 & ~x2) | (~x1 & x2 & z2)))
320364

321-
@qubitop2 CZSWAP (x2 , z2x1 , x1 , x2z1 , ~iszero((x1 & ~z1 & x2 & z2) | (x1 & z1 & x2 & ~z2)))
322-
@qubitop2 CXSWAP (x2x1 , z2 , x1 , z2z1 , ~iszero((x1 & ~z1 &~x2 & z2) | (x1 & z1 & x2 & z2)))
365+
@qubitop2 CZSWAP (x2 , z2x1 , x1 , x2z1 , ~iszero((x1 & ~z1 & x2 & z2) | (x1 & z1 & x2 & ~z2))) (x2 , z2x1 , x1 , x2z1 , ~iszero((x1 & ~z1 & x2 & z2) | (x1 & z1 & x2 & ~z2)))
366+
@qubitop2 CXSWAP (x2x1 , z2 , x1 , z2z1 , ~iszero((x1 & ~z1 &~x2 & z2) | (x1 & z1 & x2 & z2))) (x2 , z2z1 , x2x1 , z1 , ~iszero((x1 & z1 & x2 & z2) | (~x1 & z1 & x2 & ~z2)))
323367

324-
@qubitop2 CNOT (x1 , z1z2 , x2x1 , z2 , ~iszero( (x1 & z1 & x2 & z2) | (x1 & z2 &~(z1|x2)) ))
325-
@qubitop2 CPHASE (x1 , z1x2 , x2 , z2x1 , ~iszero( (x1 & z1 & x2 &~z2) | (x1 &~z1 & x2 & z2) ))
368+
@qubitop2 CNOT (x1 , z1z2 , x2x1 , z2 , ~iszero( (x1 & z1 & x2 & z2) | (x1 & z2 &~(z1|x2)) )) (x1 , z1z2 , x2x1 , z2 , ~iszero( (x1 & z1 & x2 & z2) | (x1 & z2 &~(z1|x2)) ))
369+
@qubitop2 CPHASE (x1 , z1x2 , x2 , z2x1 , ~iszero( (x1 & z1 & x2 &~z2) | (x1 &~z1 & x2 & z2) )) (x1 , z1x2 , x2 , z2x1 , ~iszero( (x1 & z1 & x2 &~z2) | (x1 &~z1 & x2 & z2) ))
326370

327-
@qubitop2 ZCX (x1 , z1z2 , x2x1 , z2 , ~iszero( ((x1 & z2) &~(z1 x2)) )) # equiv of CNOT[1, 2]
328-
@qubitop2 ZCY (x1 , x2z1z2 , x2x1 , z2x1 , ~iszero( (x1 & (x2 z1) & (x2 z2)) ))
329-
@qubitop2 ZCZ (x1 , z1x2 , x2 , z2x1 , ~iszero( ((z1 z2) & (x1 & x2)) ))
371+
@qubitop2 ZCX (x1 , z1z2 , x2x1 , z2 , ~iszero( ((x1 & z2) &~(z1 x2)) )) (x1 , z1z2 , x2x1 , z2 , ~iszero( ((x1 & z2) &~(z1 x2)) )) # equiv of CNOT[1, 2]
372+
@qubitop2 ZCY (x1 , x2z1z2 , x2x1 , z2x1 , ~iszero( (x1 & (x2 z1) & (x2 z2)) )) (x1 , x2z1z2 , x2x1 , z2x1 , ~iszero( (x1 & (x2 z1) & (x2 z2)) ))
373+
@qubitop2 ZCZ (x1 , z1x2 , x2 , z2x1 , ~iszero( ((z1 z2) & (x1 & x2)) )) (x1 , z1x2 , x2 , z2x1 , ~iszero( ((z1 z2) & (x1 & x2)) ))
330374

331-
@qubitop2 XCX (z2x1 , z1 , x2z1 , z2 , ~iszero( (z1 & z2) & (x1 x2) ))
332-
@qubitop2 XCY (x1x2z2, z1 , z1x2 , z2z1 , ~iszero( (z1 & (x2 z2) & ~(x2 x1)) ))
333-
@qubitop2 XCZ (x1x2 , z1 , x2 , z2z1 , ~iszero( (x2 & z1) & ~(x1 z2) )) # equiv to CNOT[2, 1]
375+
@qubitop2 XCX (z2x1 , z1 , x2z1 , z2 , ~iszero( (z1 & z2) & (x1 x2) )) (z2x1 , z1 , x2z1 , z2 , ~iszero( (z1 & z2) & (x1 x2) ))
376+
@qubitop2 XCY (x1x2z2, z1 , z1x2 , z2z1 , ~iszero( (z1 & (x2 z2) & ~(x2 x1)) )) (x1x2z2, z1 , z1x2 , z2z1 , ~iszero( (z1 & (x2 z2) & ~(x2 x1)) ))
377+
@qubitop2 XCZ (x1x2 , z1 , x2 , z2z1 , ~iszero( (x2 & z1) & ~(x1 z2) )) (x1x2 , z1 , x2 , z2z1 , ~iszero( (x2 & z1) & ~(x1 z2) )) # equiv to CNOT[2, 1]
334378

335-
@qubitop2 YCX (x1z2 , z2z1 , x1z1x2 , z2 , ~iszero( (z2 & (x1 z1) & ~(x2 x1)) ))
336-
@qubitop2 YCY (x1z2x2, z1x2z2 , x1x2z1 , x1z1z2, ~iszero( (x1 & ~z1 & ~x2 & z2) | (~x1 & z1 & x2 & ~z2)))
337-
@qubitop2 YCZ (x1x2 , x2z1 , x2 , z2x1z1, ~iszero( (x2 & (x1 z1) & (z2 x1)) ))
379+
@qubitop2 YCX (x1z2 , z2z1 , x1z1x2 , z2 , ~iszero( (z2 & (x1 z1) & ~(x2 x1)) )) (x1z2 , z2z1 , x1z1x2 , z2 , ~iszero( (z2 & (x1 z1) & ~(x2 x1)) ))
380+
@qubitop2 YCY (x1z2x2, z1x2z2 , x1x2z1 , x1z1z2, ~iszero( (x1 & ~z1 & ~x2 & z2) | (~x1 & z1 & x2 & ~z2))) (x1z2x2, z1x2z2 , x1x2z1 , x1z1z2, ~iszero( (x1 & ~z1 & ~x2 & z2) | (~x1 & z1 & x2 & ~z2)))
381+
@qubitop2 YCZ (x1x2 , x2z1 , x2 , z2x1z1, ~iszero( (x2 & (x1 z1) & (z2 x1)) )) (x1x2 , x2z1 , x2 , z2x1z1, ~iszero( (x2 & (x1 z1) & (z2 x1)) ))
338382

339-
@qubitop2 ZCrY (x1, x1z1x2z2, x1x2, x1z2, ~iszero((x1 &~z1 & x2) | (x1 & ~z1 & ~z2) | (x1 & x2 & ~z2)))
340-
@qubitop2 InvZCrY (x1, x1z1x2z2, x1x2, x1z2, ~iszero((x1 & z1 &~x2) | (x1 & z1 & z2) | (x1 &~x2 & z2)))
383+
@qubitop2 ZCrY (x1, x1z1x2z2, x1x2, x1z2, ~iszero((x1 &~z1 & x2) | (x1 & ~z1 & ~z2) | (x1 & x2 & ~z2))) (x1, x1z1x2z2, x1x2, x1z2, ~iszero((x1 & z1 &~x2) | (x1 & z1 & z2) | (x1 &~x2 & z2)))
384+
@qubitop2 InvZCrY (x1, x1z1x2z2, x1x2, x1z2, ~iszero((x1 & z1 &~x2) | (x1 & z1 & z2) | (x1 &~x2 & z2))) (x1, x1z1x2z2, x1x2, x1z2, ~iszero((x1 &~z1 & x2) | (x1 & ~z1 & ~z2) | (x1 & x2 & ~z2)))
341385

342-
@qubitop2 SQRTZZ (x1 , x1x2z1 , x2 , x1z2x2 , ~iszero((x1 & z1 & ~x2) | (~x1 & x2 & z2)))
343-
@qubitop2 InvSQRTZZ (x1 , x1x2z1 , x2 , x1z2x2 , ~iszero((x1 &~z1 & ~x2) | (~x1 & x2 &~z2)))
386+
@qubitop2 SQRTZZ (x1 , x1x2z1 , x2 , x1z2x2 , ~iszero((x1 & z1 & ~x2) | (~x1 & x2 & z2))) (x1 , x1x2z1 , x2 , x1z2x2 , ~iszero((x1 &~z1 & ~x2) | (~x1 & x2 &~z2)))
387+
@qubitop2 InvSQRTZZ (x1 , x1x2z1 , x2 , x1z2x2 , ~iszero((x1 &~z1 & ~x2) | (~x1 & x2 &~z2))) (x1 , x1x2z1 , x2 , x1z2x2 , ~iszero((x1 & z1 & ~x2) | (~x1 & x2 & z2)))
344388

345-
@qubitop2 SQRTXX (z1z2x1, z1 , z1x2z2, z2 , ~iszero((~x1 & z1 &~z2) | (~z1 &~x2 & z2)))
346-
@qubitop2 InvSQRTXX (z1z2x1, z1 , z1x2z2, z2 , ~iszero(( x1 & z1 &~z2) | (~z1 & x2 & z2)))
389+
@qubitop2 SQRTXX (z1z2x1, z1 , z1x2z2, z2 , ~iszero((~x1 & z1 &~z2) | (~z1 &~x2 & z2))) (z1z2x1, z1 , z1x2z2, z2 , ~iszero(( x1 & z1 &~z2) | (~z1 & x2 & z2)))
390+
@qubitop2 InvSQRTXX (z1z2x1, z1 , z1x2z2, z2 , ~iszero(( x1 & z1 &~z2) | (~z1 & x2 & z2))) (z1z2x1, z1 , z1x2z2, z2 , ~iszero((~x1 & z1 &~z2) | (~z1 &~x2 & z2)))
347391

348-
@qubitop2 SQRTYY (z1x2z2, x1z2x2, x1z1z2, x1x2z1, ~iszero((~x1 &~z1 & x2 &~z2) | ( x1 &~z1 &~x2 &~z2) | ( x1 &~z1 & x2 & z2) | ( x1 & z1 & x2 &~z2)))
349-
@qubitop2 InvSQRTYY (z1x2z2, x1z2x2, x1z1z2, x1x2z1, ~iszero(( x1 & z1 &~x2 & z2) | (~x1 & z1 & x2 & z2) | (~x1 & z1 &~x2 &~z2) | (~x1 &~z1 &~x2 & z2)))
392+
@qubitop2 SQRTYY (z1x2z2, x1z2x2, x1z1z2, x1x2z1, ~iszero((~x1 &~z1 & x2 &~z2) | ( x1 &~z1 &~x2 &~z2) | ( x1 &~z1 & x2 & z2) | ( x1 & z1 & x2 &~z2))) (z1x2z2, x1z2x2, x1z1z2, x1x2z1, ~iszero(( x1 & z1 &~x2 & z2) | (~x1 & z1 & x2 & z2) | (~x1 & z1 &~x2 &~z2) | (~x1 &~z1 &~x2 & z2)))
393+
@qubitop2 InvSQRTYY (z1x2z2, x1z2x2, x1z1z2, x1x2z1, ~iszero(( x1 & z1 &~x2 & z2) | (~x1 & z1 & x2 & z2) | (~x1 & z1 &~x2 &~z2) | (~x1 &~z1 &~x2 & z2))) (z1x2z2, x1z2x2, x1z1z2, x1x2z1, ~iszero((~x1 &~z1 & x2 &~z2) | ( x1 &~z1 &~x2 &~z2) | ( x1 &~z1 & x2 & z2) | ( x1 & z1 & x2 &~z2)))
350394

351395
#=
352396
To get the boolean formulas for the phase, it is easiest to first write down the truth table for the phase:

0 commit comments

Comments
 (0)