Skip to content

Commit

Permalink
inv implementation for TwoQubitOperator (#315)
Browse files Browse the repository at this point in the history
Co-authored-by: Fe-r-oz <ferozahmad7cf@gmail.com>
Co-authored-by: Stefan Krastanov <stefan@krastanov.org>
  • Loading branch information
3 people authored Aug 5, 2024
1 parent dad8484 commit 263195c
Show file tree
Hide file tree
Showing 10 changed files with 68 additions and 9 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@

# News

## v0.9.9 - 2024-08-05

- `inv` is implemented for all Clifford operator types (symbolic, dense, sparse).

## v0.9.8 - 2024-08-03

- New group-theoretical tools:
Expand Down
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "QuantumClifford"
uuid = "0525e862-1e90-11e9-3e4d-1b39d7109de1"
authors = ["Stefan Krastanov <stefan@krastanov.org> and QuantumSavory community members"]
version = "0.9.8"
version = "0.9.9"

[deps]
Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa"
Expand Down
2 changes: 1 addition & 1 deletion src/QuantumClifford.jl
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export
sHadamard, sPhase, sInvPhase, SingleQubitOperator, sId1, sX, sY, sZ,
sCNOT, sCPHASE, sSWAP,
sXCX, sXCY, sXCZ, sYCX, sYCY, sYCZ, sZCX, sZCY, sZCZ,
sZCrY,
sZCrY, sInvZCrY,
# Misc Ops
SparseGate,
sMX, sMY, sMZ, PauliMeasurement, Reset, sMRX, sMRY, sMRZ,
Expand Down
4 changes: 4 additions & 0 deletions src/misc_ops.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ function apply!(state::AbstractStabilizer, g::SparseGate; kwargs...)
apply!(state, g.cliff, g.indices; kwargs...)
end

function LinearAlgebra.inv(g::SparseGate; phases=true)
return SparseGate(inv(g.cliff;phases=phases), g.indices)
end

"""Reset the specified qubits to the given state.
Be careful, this operation implies first tracing out the qubits, which can lead to mixed states
Expand Down
5 changes: 1 addition & 4 deletions src/noise.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,14 @@ struct PauliNoise{T} <: AbstractNoise
py::T
pz::T
end

function PauliNoise(px::Real, py::Real, pz::Real)
px, py, pz = float.((px, py, pz))
px, py, pz = promote(px, py, pz)
T = typeof(px)
return PauliNoise{T}(px, py, pz)
end

"""A convenient constructor for various types of Pauli noise models.
Returns more specific types when necessary."""
function PauliNoise end

"""Constructs an unbiased Pauli noise model with total probability of error `p`."""
function PauliNoise(p)
UnbiasedUncorrelatedNoise(p)
Expand Down
8 changes: 7 additions & 1 deletion src/pauli_operator.jl
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,13 @@ Base.hash(p::PauliOperator, h::UInt) = hash(p.phase,hash(p.nqubits,hash(p.xz, h)

Base.copy(p::PauliOperator) = PauliOperator(copy(p.phase),p.nqubits,copy(p.xz))

function Base.deleteat!(p::PauliOperator, subset)
function LinearAlgebra.inv(p::PauliOperator)
ph = p.phase[]
phin = xor((ph << 1) & ~(UInt8(1) << 2), ph)
return PauliOperator(phin, p.nqubits, copy(p.xz))
end

function Base.deleteat!(p::PauliOperator, subset)
p =p[setdiff(1:length(p), subset)]
return p
end
Expand Down
16 changes: 16 additions & 0 deletions src/symbolic_cliffords.jl
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ end
@qubitop2 YCZ (x1x2 , x2z1 , x2 , z2x1z1, ~iszero( (x2 & (x1 z1) & (z2 x1)) ))

@qubitop2 ZCrY (x1, x1z1x2z2, x1x2, x1z2, ~iszero((x1 & ~z1 & x2) | (x1 & ~z1 & ~z2) | (x1 & x2 & ~z2)))
@qubitop2 InvZCrY (x1, x1z1x2z2, x1x2, x1z2, ~iszero((x1 & z1 & ~x2 & ~z2) | (x1 & ~z1 & ~x2 & z2) | (x1 & z1 & ~x2 & z2) | (x1 & z1 & x2 & z2)))

#=
To get the boolean formulas for the phase, it is easiest to first write down the truth table for the phase:
Expand Down Expand Up @@ -346,6 +347,21 @@ function Base.show(io::IO, op::AbstractTwoQubitOperator)
end
end

LinearAlgebra.inv(op::sSWAP) = sSWAP(op.q1, op.q2)
LinearAlgebra.inv(op::sCNOT) = sCNOT(op.q1, op.q2)
LinearAlgebra.inv(op::sCPHASE) = sCPHASE(op.q1, op.q2)
LinearAlgebra.inv(op::sZCX) = sZCX(op.q1, op.q2)
LinearAlgebra.inv(op::sZCY) = sZCY(op.q1, op.q2)
LinearAlgebra.inv(op::sZCZ) = sZCZ(op.q1, op.q2)
LinearAlgebra.inv(op::sXCX) = sXCX(op.q1, op.q2)
LinearAlgebra.inv(op::sXCY) = sXCY(op.q1, op.q2)
LinearAlgebra.inv(op::sXCZ) = sXCZ(op.q1, op.q2)
LinearAlgebra.inv(op::sYCX) = sYCX(op.q1, op.q2)
LinearAlgebra.inv(op::sYCY) = sYCY(op.q1, op.q2)
LinearAlgebra.inv(op::sYCZ) = sYCZ(op.q1, op.q2)
LinearAlgebra.inv(op::sZCrY) = sInvZCrY(op.q1, op.q2)
LinearAlgebra.inv(op::sInvZCrY) = sZCrY(op.q1, op.q2)

##############################
# Functions that perform direct application of common operators without needing an operator instance
##############################
Expand Down
18 changes: 16 additions & 2 deletions test/test_noisycircuits.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,16 @@
test_sizes = [1,2,10,63,64,65,127,128,129] # Including sizes that would test off-by-one errors in the bit encoding.

using QuantumClifford.Experimental.NoisyCircuits

import AbstractAlgebra

@testset "SparseGate" begin
g = SparseGate(random_clifford(2), randperm(10)[1:2])
gi = inv(g)
c = random_stabilizer(10)
@assert apply!(apply!(copy(c), g), gi) == c
end

@testset "Noisy Gates" begin
g1 = SparseGate(tId1, [1])
g2 = SparseGate(tCNOT, [2,3])
Expand All @@ -25,6 +33,7 @@
resp = petrajectories(copy(state), [ng1,ng2,ng3,ng4,ng5])
@test all(values(resp).==0)
end

@testset "Monte Carlo Purification examples" begin
g1 = SparseGate(tCNOT, [1,3])
g2 = SparseGate(tCNOT, [2,4])
Expand All @@ -49,8 +58,6 @@
@test nonoise[true_success_stat] == 10
end



@testset "Perturbative expansion Purification examples" begin
@testset "Comparison to MC" begin
compare(a,b, symbol) = abs(a[symbol]/500-b[symbol]) / (a[symbol]/500+b[symbol]+1e-5) < 0.3
Expand Down Expand Up @@ -79,6 +86,7 @@
@test compare(mc,pe,false_success_stat)
@test compare(mc,pe,true_success_stat)
end

@testset "Symbolic" begin
R, (e,) = AbstractAlgebra.polynomial_ring(AbstractAlgebra.RealField, ["e"])
unity = R(1);
Expand All @@ -97,6 +105,7 @@
@test pe_symbolic[true_success_stat] == 27.0*e^4 + -54.0*e^3 + 36.0*e^2 + -10.0*e + 1.0
end
end

@testset "Measurements" begin
@testset "BellMeasurements" begin
stateX = S"X"
Expand Down Expand Up @@ -138,6 +147,7 @@
@test random2_pe[failure_stat]+random2_pe[false_success_stat] == 1
@test random2_pe[true_success_stat] == 0
end

@testset "PauliMeasurements" begin
ghzState = S"XXX
ZZI
Expand Down Expand Up @@ -174,6 +184,7 @@
@test random2_pe[false_success_stat] == 1
@test random2_pe[true_success_stat] == 0
end

@testset "Sparse Measurements" begin
ghzState = S"XXX
ZZI
Expand Down Expand Up @@ -212,6 +223,7 @@
@test random2_pe[false_success_stat] == 1
@test random2_pe[true_success_stat] == 0
end

@testset "Conforming to the project! interface" begin
state = Register(MixedDestabilizer(S"ZZ"), zeros(Bool, 1))
meas = PauliMeasurement(P"ZI", 1)
Expand All @@ -222,6 +234,7 @@
ZI"
end
end

@testset "Classical Bits" begin
@testset "DecisionGate" begin
X_error = CliffordOperator([P"X", P"-Z"])
Expand Down Expand Up @@ -256,6 +269,7 @@
canonicalize!(quantumstate(r))
@test stabilizerview(r) == expectedFinalState
end

@testset "ConditionalGate" begin
id_op = CliffordOperator([P"X", P"Z"])
X_error = CliffordOperator([P"X", P"-Z"])
Expand Down
5 changes: 5 additions & 0 deletions test/test_paulis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@
@test prodphase(P"XX",P"YY") == 0x2
@test prodphase(P"ZZZ",P"XXX") == prodphase(S"III ZZZ",P"XXX",2) == prodphase(P"ZZZ",S"III XXX",2) == prodphase(S"III ZZZ",S"III XXX",2,2) == 0x3
end

for Pop in [P"X", P"iX", P"-iXYZ", random_pauli(100; nophase=false, realphase=false)]
@test Pop * inv(Pop) == zero(Pop)
end

@testset "Commutation implies real phase" begin
for i in 1:10
for n in test_sizes
Expand Down
13 changes: 13 additions & 0 deletions test/test_symcliff.jl
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,17 @@
@test CliffordOperator(inv(SingleQubitOperator(random_op)), i) == inv(CliffordOperator(random_op, i))
end
end

@testset "TwoQubitOperator inv methods" begin
for gate_type in subtypes(QuantumClifford.AbstractTwoQubitOperator)
n₁ = rand(2: 10)
n₂ = rand(1:(n₁ - 1))
@test CliffordOperator(inv(gate_type(n₁, n₂)), n₁) == inv(CliffordOperator(gate_type(n₁, n₂), n₁))
@test CliffordOperator(inv(gate_type(n₂, n₁)), n₁) == inv(CliffordOperator(gate_type(n₂, n₁), n₁))
@test CliffordOperator(inv(sZCX(n₁, n₂)), n₁) == inv(CliffordOperator(sCNOT(n₁, n₂), n₁))
@test CliffordOperator(inv(sXCZ(n₁, n₂)), n₁) == inv(CliffordOperator(sCNOT(n₂, n₁), n₁))
@test CliffordOperator(inv(sZCrY(n₁, n₂)), n₁) == inv(CliffordOperator(sZCrY(n₁, n₂), n₁))
@test CliffordOperator(inv(sInvZCrY(n₁, n₂)), n₁) == inv(CliffordOperator(sInvZCrY(n₁, n₂), n₁))
end
end
end

0 comments on commit 263195c

Please sign in to comment.