diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d46dc8c..2ee7c838 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ## dev +- Implementing many more named single-qubit gates following naming convention similar to the stim package in python. - **(fix)** Bug fix to the `parity_checks(ReedMuller(r, m))` of classical Reed-Muller code (it was returning generator matrix). - `RecursiveReedMuller` code implementation as an alternative implementation of `ReedMuller`. diff --git a/src/QuantumClifford.jl b/src/QuantumClifford.jl index d54ec03b..5d0eff1b 100644 --- a/src/QuantumClifford.jl +++ b/src/QuantumClifford.jl @@ -48,6 +48,7 @@ export # Symbolic Clifford Ops AbstractSymbolicOperator, AbstractSingleQubitOperator, AbstractTwoQubitOperator, sHadamard, sPhase, sInvPhase, SingleQubitOperator, sId1, sX, sY, sZ, + sHadamardXY, sHadamardYZ, sSQRTX, sInvSQRTX, sSQRTY, sInvSQRTY, sCXYZ, sCZYX, sCNOT, sCPHASE, sSWAP, sXCX, sXCY, sXCZ, sYCX, sYCY, sYCZ, sZCX, sZCY, sZCZ, sZCrY, sInvZCrY, diff --git a/src/symbolic_cliffords.jl b/src/symbolic_cliffords.jl index 38be9eeb..78160992 100644 --- a/src/symbolic_cliffords.jl +++ b/src/symbolic_cliffords.jl @@ -85,12 +85,20 @@ macro qubitop1(name, kernel) end end -@qubitop1 Hadamard (z , x , x!=0 && z!=0) -@qubitop1 Phase (x , x⊻z , x!=0 && z!=0) -@qubitop1 InvPhase (x , x⊻z , x!=0 && z==0) -@qubitop1 X (x , z , z!=0) -@qubitop1 Y (x , z , (x⊻z)!=0) -@qubitop1 Z (x , z , x!=0) +@qubitop1 Hadamard (z ,x , x!=0 && z!=0) +@qubitop1 HadamardXY (x ,x⊻z , x==0 && z!=0) +@qubitop1 HadamardYZ (x⊻z ,z , x!=0 && z==0) +@qubitop1 Phase (x ,x⊻z , x!=0 && z!=0) +@qubitop1 InvPhase (x ,x⊻z , x!=0 && z==0) +@qubitop1 X (x ,z , z!=0) +@qubitop1 Y (x ,z , (x⊻z)!=0) +@qubitop1 Z (x ,z , x!=0) +@qubitop1 SQRTX (x⊻z ,z , x==0 && z!=0) +@qubitop1 InvSQRTX (x⊻z ,z , x!=0 && z!=0) +@qubitop1 SQRTY (z ,x , z==0) +@qubitop1 InvSQRTY (z ,x , z!=0 && x==0) +@qubitop1 CXYZ (x⊻z ,x , z==0 && x==0) +@qubitop1 CZYX (z ,x⊻z , z==0 && x==0) """A "symbolic" single-qubit Identity operation. @@ -177,13 +185,21 @@ function _apply!(stab::AbstractStabilizer, op::SingleQubitOperator; phases::Val{ stab end -SingleQubitOperator(h::sHadamard) = SingleQubitOperator(h.q, false, true , true , false, false, false) -SingleQubitOperator(p::sPhase) = SingleQubitOperator(p.q, true , true , false, true , false, false) -SingleQubitOperator(p::sInvPhase) = SingleQubitOperator(p.q, true , true , false, true , true , false) -SingleQubitOperator(p::sId1) = SingleQubitOperator(p.q, true , false, false, true , false, false) -SingleQubitOperator(p::sX) = SingleQubitOperator(p.q, true , false, false, true , false, true) -SingleQubitOperator(p::sY) = SingleQubitOperator(p.q, true , false, false, true , true , true) -SingleQubitOperator(p::sZ) = SingleQubitOperator(p.q, true , false, false, true , true , false) +SingleQubitOperator(h::sHadamard) = SingleQubitOperator(h.q, false, true , true , false, false, false) +SingleQubitOperator(p::sPhase) = SingleQubitOperator(p.q, true , true , false, true , false, false) +SingleQubitOperator(p::sInvPhase) = SingleQubitOperator(p.q, true , true , false, true , true , false) +SingleQubitOperator(p::sId1) = SingleQubitOperator(p.q, true , false, false, true , false, false) +SingleQubitOperator(p::sX) = SingleQubitOperator(p.q, true , false, false, true , false, true) +SingleQubitOperator(p::sY) = SingleQubitOperator(p.q, true , false, false, true , true , true) +SingleQubitOperator(p::sZ) = SingleQubitOperator(p.q, true , false, false, true , true , false) +SingleQubitOperator(p::sCXYZ) = SingleQubitOperator(p.q, true , true , true , false, false, false) +SingleQubitOperator(p::sCZYX) = SingleQubitOperator(p.q, false, true , true , true , false, false) +SingleQubitOperator(p::sHadamardXY) = SingleQubitOperator(p.q, true , true , false, true , false, true) +SingleQubitOperator(p::sHadamardYZ) = SingleQubitOperator(p.q, true , false, true , true , true , false) +SingleQubitOperator(p::sSQRTX) = SingleQubitOperator(p.q, true , false, true , true , false, true) +SingleQubitOperator(p::sInvSQRTX) = SingleQubitOperator(p.q, true , false, true , true , false, false) +SingleQubitOperator(p::sSQRTY) = SingleQubitOperator(p.q, false, true , true , false, true , false) +SingleQubitOperator(p::sInvSQRTY) = SingleQubitOperator(p.q, false, true , true , false, false, true) SingleQubitOperator(o::SingleQubitOperator) = o function SingleQubitOperator(op::CliffordOperator, qubit) nqubits(op)==1 || throw(DimensionMismatch("You are trying to convert a multiqubit `CliffordOperator` into a symbolic `SingleQubitOperator`.")) @@ -232,14 +248,21 @@ function LinearAlgebra.inv(op::SingleQubitOperator) return SingleQubitOperator(c, op.q) end -LinearAlgebra.inv(h::sHadamard) = sHadamard(h.q) -LinearAlgebra.inv(p::sPhase) = sInvPhase(p.q) -LinearAlgebra.inv(p::sInvPhase) = sPhase(p.q) -LinearAlgebra.inv(p::sId1) = sId1(p.q) -LinearAlgebra.inv(p::sX) = sX(p.q) -LinearAlgebra.inv(p::sY) = sY(p.q) -LinearAlgebra.inv(p::sZ) = sZ(p.q) - +LinearAlgebra.inv(h::sHadamard) = sHadamard(h.q) +LinearAlgebra.inv(p::sPhase) = sInvPhase(p.q) +LinearAlgebra.inv(p::sInvPhase) = sPhase(p.q) +LinearAlgebra.inv(p::sId1) = sId1(p.q) +LinearAlgebra.inv(p::sX) = sX(p.q) +LinearAlgebra.inv(p::sY) = sY(p.q) +LinearAlgebra.inv(p::sZ) = sZ(p.q) +LinearAlgebra.inv(p::sHadamardXY) = sHadamardXY(p.q) +LinearAlgebra.inv(p::sHadamardYZ) = sHadamardYZ(p.q) +LinearAlgebra.inv(p::sSQRTX) = sInvSQRTX(p.q) +LinearAlgebra.inv(p::sInvSQRTX) = sSQRTX(p.q) +LinearAlgebra.inv(p::sSQRTY) = sInvSQRTY(p.q) +LinearAlgebra.inv(p::sInvSQRTY) = sSQRTY(p.q) +LinearAlgebra.inv(p::sCZYX) = sCXYZ(p.q) +LinearAlgebra.inv(p::sCXYZ) = sCZYX(p.q) ############################## # Two-qubit gates ############################## diff --git a/test/test_symcliff.jl b/test/test_symcliff.jl index 753d8284..1d9f2dbe 100644 --- a/test/test_symcliff.jl +++ b/test/test_symcliff.jl @@ -66,7 +66,7 @@ end @testset "SingleQubitOperator inv methods" begin - for gate_type in [sHadamard, sX, sY, sZ, sId1 , sPhase, sInvPhase] + for gate_type in filter(gate_type -> gate_type != SingleQubitOperator, subtypes(AbstractSingleQubitOperator)) n = rand(1:10) @test CliffordOperator(inv(SingleQubitOperator(gate_type(n))), n) == inv(CliffordOperator(gate_type(n), n)) @test CliffordOperator(inv(gate_type(n)), n) == inv(CliffordOperator(gate_type(n), n)) @@ -76,6 +76,17 @@ @test CliffordOperator(inv(random_op), i) == inv(CliffordOperator(random_op, i)) @test CliffordOperator(inv(SingleQubitOperator(random_op)), i) == inv(CliffordOperator(random_op, i)) end + + @testset "Consistency checks with Stim" begin + # see https://github.com/quantumlib/Stim/blob/main/doc/gates.md + @test CliffordOperator(sCXYZ) == C"Y X" + @test CliffordOperator(sCZYX) == C"Z Y" + @test CliffordOperator(sSQRTX) == C"X -Y" + @test CliffordOperator(sSQRTY) == C"-Z X" + @test CliffordOperator(sInvSQRTX) == C"X Y" + @test CliffordOperator(sInvSQRTY) == C"Z -X" + @test CliffordOperator(sHadamardXY) == C"Y -Z" + @test CliffordOperator(sHadamardYZ) == C"-X Y" end @testset "TwoQubitOperator inv methods" begin