Skip to content

Commit

Permalink
Merge branch 'master' into lift-dev-hecke
Browse files Browse the repository at this point in the history
  • Loading branch information
royess authored Sep 15, 2024
2 parents e24a19b + 05491d9 commit 393bbfc
Show file tree
Hide file tree
Showing 10 changed files with 175 additions and 100 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.

Expand Down
33 changes: 26 additions & 7 deletions src/QuantumClifford.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -149,11 +150,20 @@ function Tableau(paulis::AbstractVector{PauliOperator{Tₚ,Tᵥ}}) where {Tₚ<:
tab
end

Tableau(phases::AbstractVector{UInt8}, xs::AbstractMatrix{Bool}, zs::AbstractMatrix{Bool}) = Tableau(
phases, size(xs,2),
vcat(hcat((BitArray(xs[i,:]).chunks for i in 1:size(xs,1))...)::Matrix{UInt},
hcat((BitArray(zs[i,:]).chunks for i in 1:size(zs,1))...)::Matrix{UInt}) # type assertions to help Julia infer types
)
function Tableau(phases::AbstractVector{UInt8}, xs::AbstractMatrix{Bool}, zs::AbstractMatrix{Bool})
r_xs = size(xs, 1)
r_zs = size(zs, 1)
if length(phases) != r_xs || r_xs != r_zs
throw(DimensionMismatch(lazy"The length of phases ($(length(phases))), rows of xs ($r_xs), rows of zs ($r_zs) must all be equal."))
end
Tableau(
phases,size(xs, 2),
vcat(
hcat((BitArray(xs[i, :]).chunks for i in 1:r_xs)...)::Matrix{UInt},
hcat((BitArray(zs[i, :]).chunks for i in 1:r_zs)...)::Matrix{UInt} # type assertions to help Julia infer types
)
)
end

Tableau(phases::AbstractVector{UInt8}, xzs::AbstractMatrix{Bool}) = Tableau(phases, xzs[:,1:end÷2], xzs[:,end÷2+1:end])

Expand Down Expand Up @@ -758,10 +768,19 @@ function comm!(v, l::PauliOperator, r::Tableau)
v
end
comm!(v, l::Tableau, r::PauliOperator) = comm!(v, r, l)
@inline comm!(v, l::PauliOperator, r::Stabilizer, i::Int) = comm!(v, l, tab(r), i)
@inline comm!(v, l::Stabilizer, r::PauliOperator, i::Int) = comm!(v, tab(l), r, i)
@inline comm!(v, l::PauliOperator, r::Stabilizer) = comm!(v, l, tab(r))
@inline comm!(v, l::Stabilizer, r::PauliOperator) = comm!(v, tab(l), r)
function comm!(v, l::PauliOperator, r::Tableau, i)
v[i] = comm(l,r,i)
v
end
comm!(v, l::Tableau, r::PauliOperator, i) = comm!(v, r, l, i)
@inline comm!(v, l::PauliOperator, r::Stabilizer, i::Int) = comm!(v, l, tab(r), i)
@inline comm!(v, l::Stabilizer, r::PauliOperator, i::Int) = comm!(v, tab(l), r, i)
function comm!(v, s::Tableau, l::Int, r::Int)
v[l] = comm(s, l, r)
v
end
@inline comm!(v, s::Stabilizer, l::Int, r::Int) = comm!(v, tab(s), l, r)


Expand Down
2 changes: 1 addition & 1 deletion src/dense_cliffords.jl
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ function row_limit(str, limit=50)
end

digits_subchars = collect("₀₁₂₃₄₅₆₇₈₉")
digits_substr(n,nwidth) = join(([digits_subchars[d+1] for d in reverse(digits(n, pad=nwidth))]))
digits_substr(n::Int,nwidth::Int) = join(([digits_subchars[d+1] for d in reverse(digits(n, pad=nwidth))]))

function Base.copy(c::CliffordOperator)
CliffordOperator(copy(c.tab))
Expand Down
5 changes: 3 additions & 2 deletions src/ecc/ECC.jl
Original file line number Diff line number Diff line change
Expand Up @@ -352,8 +352,9 @@ isdegenerate(c::AbstractECC, args...) = isdegenerate(parity_checks(c), args...)
isdegenerate(c::AbstractStabilizer, args...) = isdegenerate(stabilizerview(c), args...)

function isdegenerate(H::Stabilizer, errors) # Described in https://quantumcomputing.stackexchange.com/questions/27279
syndromes = comm.((H,), errors) # TODO This can be optimized by having something that always returns bitvectors
return length(Set(syndromes)) != length(errors)
syndromes = map(e -> comm(H,e), errors) # TODO This can be optimized by having something that always returns bitvectors
syndrome_set = Set(syndromes)
return length(syndrome_set) != length(errors)
end

function isdegenerate(H::Stabilizer, d::Int=1)
Expand Down
2 changes: 1 addition & 1 deletion src/ecc/decoder_pipeline.jl
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ function evaluate_decoder(d::AbstractSyndromeDecoder, setup::AbstractECCSetup, n

physical_noisy_circ, syndrome_bits, n_anc = physical_ECC_circuit(H, setup)
encoding_circ = naive_encoding_circuit(H)
preX = [sHadamard(i) for i in n-k+1:n]
preX = sHadamard[sHadamard(i) for i in n-k+1:n]

mdH = MixedDestabilizer(H)
logX_circ, _, logX_bits = naive_syndrome_circuit(logicalxview(mdH), n_anc+1, last(syndrome_bits)+1)
Expand Down
10 changes: 10 additions & 0 deletions src/misc_ops.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,21 @@ end
struct SparseGate{T<:Tableau} <: AbstractCliffordOperator # TODO simplify type parameters (remove nesting)
cliff::CliffordOperator{T}
indices::Vector{Int}
function SparseGate(cliff::CliffordOperator{T}, indices::Vector{Int}) where T<:Tableau
if length(indices) != nqubits(cliff)
throw(ArgumentError("The number of target qubits (indices) must match the qubit count in the CliffordOperator."))
end
new{T}(cliff, indices)
end
end

SparseGate(c,t::Tuple) = SparseGate(c,collect(t))

function apply!(state::AbstractStabilizer, g::SparseGate; kwargs...)
m = maximum(g.indices)
if m > nqubits(state)
throw(ArgumentError(lazy"SparseGate was attempted on invalid qubit index $(m) when the state contains only $(nqubits(state)) qubits."))
end
apply!(state, g.cliff, g.indices; kwargs...)
end

Expand Down
65 changes: 44 additions & 21 deletions src/symbolic_cliffords.jl
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,20 @@ macro qubitop1(name, kernel)
end
end

@qubitop1 Hadamard (z , x , x!=0 && z!=0)
@qubitop1 Phase (x , xz , x!=0 && z!=0)
@qubitop1 InvPhase (x , xz , x!=0 && z==0)
@qubitop1 X (x , z , z!=0)
@qubitop1 Y (x , z , (xz)!=0)
@qubitop1 Z (x , z , x!=0)
@qubitop1 Hadamard (z ,x , x!=0 && z!=0)
@qubitop1 HadamardXY (x ,xz , x==0 && z!=0)
@qubitop1 HadamardYZ (xz ,z , x!=0 && z==0)
@qubitop1 Phase (x ,xz , x!=0 && z!=0)
@qubitop1 InvPhase (x ,xz , x!=0 && z==0)
@qubitop1 X (x ,z , z!=0)
@qubitop1 Y (x ,z , (xz)!=0)
@qubitop1 Z (x ,z , x!=0)
@qubitop1 SQRTX (xz ,z , x==0 && z!=0)
@qubitop1 InvSQRTX (xz ,z , x!=0 && z!=0)
@qubitop1 SQRTY (z ,x , z==0)
@qubitop1 InvSQRTY (z ,x , z!=0 && x==0)
@qubitop1 CXYZ (xz ,x , z==0 && x==0)
@qubitop1 CZYX (z ,xz , z==0 && x==0)

"""A "symbolic" single-qubit Identity operation.
Expand Down Expand Up @@ -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`."))
Expand Down Expand Up @@ -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
##############################
Expand Down
47 changes: 25 additions & 22 deletions test/test_jet.jl
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
@testitem "JET checks" tags=[:jet] begin
using JET
using ArrayInterface
using Static
using Graphs
using StridedViews
using LinearAlgebra
using AbstractAlgebra, Hecke
using JET
using Test
using ArrayInterface
using Static
using Graphs
using StridedViews
using LinearAlgebra
using Nemo
using AbstractAlgebra
using Hecke

rep = report_package("QuantumClifford";
ignored_modules=(
AnyFrameModule(Graphs.LinAlg),
AnyFrameModule(Graphs.SimpleGraphs),
AnyFrameModule(ArrayInterface),
AnyFrameModule(Static),
AnyFrameModule(StridedViews),
AnyFrameModule(LinearAlgebra),
AnyFrameModule(Nemo),
AnyFrameModule(AbstractAlgebra),
AnyFrameModule(Hecke),
))

rep = report_package("QuantumClifford";
ignored_modules=(
AnyFrameModule(Graphs.LinAlg),
AnyFrameModule(Graphs.SimpleGraphs),
AnyFrameModule(ArrayInterface),
AnyFrameModule(Static),
AnyFrameModule(StridedViews),
AnyFrameModule(LinearAlgebra),
AnyFrameModule(Hecke),
AnyFrameModule(AbstractAlgebra),
)
)
@show rep
@test_broken length(JET.get_reports(rep)) == 0
@test length(JET.get_reports(rep)) <= 23
@show rep
@test_broken length(JET.get_reports(rep)) == 0
@test length(JET.get_reports(rep)) <= 11
end
13 changes: 12 additions & 1 deletion test/test_symcliff.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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
Expand Down
97 changes: 52 additions & 45 deletions test/test_throws.jl
Original file line number Diff line number Diff line change
@@ -1,66 +1,73 @@
@testitem "throws" begin
using QuantumClifford: rank, mul_left!, mul_right!
using InteractiveUtils: subtypes
using QuantumClifford: rank, mul_left!, mul_right!
using InteractiveUtils: subtypes

@test_throws DimensionMismatch CliffordOperator(T"XXX ZZ_")
@test_throws DimensionMismatch CliffordOperator(T"XXX ZZ_")

@test_throws DimensionMismatch tCNOT*S"X"
@test_throws DimensionMismatch tCNOT*S"X"

#@test_throws DomainError bigram(random_stabilizer(50), clip=false)
#@test_throws DomainError bigram(random_stabilizer(50), clip=false)

@test_throws DomainError logdot(S"XX", S"XX ZZ")
@test_throws DimensionMismatch logdot(S"X", S"XX ZZ")
@test_throws DomainError logdot(S"XX", S"XX ZZ")
@test_throws DimensionMismatch logdot(S"X", S"XX ZZ")

@test_throws BadDataStructure rank(S"X")
@test_throws BadDataStructure rank(Destabilizer(S"X"))
@test_throws BadDataStructure rank(S"X")
@test_throws BadDataStructure rank(Destabilizer(S"X"))

@test_throws DimensionMismatch mul_left!(P"X", P"XX")
@test_throws DimensionMismatch mul_right!(P"X", P"XX")
@test_throws DimensionMismatch mul_left!(P"X", P"XX")
@test_throws DimensionMismatch mul_right!(P"X", P"XX")

@test_throws ArgumentError StabMixture(S"XX")
@test_throws ArgumentError StabMixture(S"XX")

@test_throws ArgumentError UnitaryPauliChannel([P"X"], [1,2])
@test_throws ArgumentError UnitaryPauliChannel([P"X",P"XX"], [1,2])
@test_throws ArgumentError UnitaryPauliChannel([P"X"], [1,2])
@test_throws ArgumentError UnitaryPauliChannel([P"X",P"XX"], [1,2])

@test_throws ArgumentError embed(10,2,P"XX")
@test_throws ArgumentError embed(10,[2,3],P"X")
@test_throws ArgumentError embed(10,2,P"XX")
@test_throws ArgumentError embed(10,[2,3],P"X")

struct A <: QuantumClifford.AbstractOperation end
@test_throws ArgumentError applybranches(S"X",A())
struct A <: QuantumClifford.AbstractOperation end
@test_throws ArgumentError applybranches(S"X",A())

@test_throws BadDataStructure project!(Destabilizer(S"XX"), P"ZZ")
@test_throws BadDataStructure project!(Destabilizer(S"XX"), P"ZZ")

@test_throws DimensionMismatch reset_qubits!(ghz(4), ghz(3), [1,2])
@test_throws DimensionMismatch reset_qubits!(ghz(3), ghz(4), [1,2,3,4])
@test_throws DimensionMismatch reset_qubits!(MixedStabilizer(ghz(4)), MixedStabilizer(ghz(3)), [1,2])
@test_throws DimensionMismatch reset_qubits!(MixedStabilizer(ghz(3)), MixedStabilizer(ghz(4)), [1,2,3,4])
@test_throws DimensionMismatch reset_qubits!(MixedDestabilizer(ghz(4)), MixedDestabilizer(ghz(3)), [1,2])
@test_throws DimensionMismatch reset_qubits!(MixedDestabilizer(ghz(3)), MixedDestabilizer(ghz(4)), [1,2,3,4])
@test_throws DimensionMismatch reset_qubits!(ghz(4), ghz(3), [1,2])
@test_throws DimensionMismatch reset_qubits!(ghz(3), ghz(4), [1,2,3,4])
@test_throws DimensionMismatch reset_qubits!(MixedStabilizer(ghz(4)), MixedStabilizer(ghz(3)), [1,2])
@test_throws DimensionMismatch reset_qubits!(MixedStabilizer(ghz(3)), MixedStabilizer(ghz(4)), [1,2,3,4])
@test_throws DimensionMismatch reset_qubits!(MixedDestabilizer(ghz(4)), MixedDestabilizer(ghz(3)), [1,2])
@test_throws DimensionMismatch reset_qubits!(MixedDestabilizer(ghz(3)), MixedDestabilizer(ghz(4)), [1,2,3,4])

#TODO broken in other ways @test_throws DomainError MixedDestabilizer(Destabilizer(S"XX"))
#TODO broken in other ways @test_throws DomainError MixedDestabilizer(Destabilizer(S"XX"))

@test_throws DomainError 2*P"X"
@test_throws DomainError 2*P"X"

@test_throws DimensionMismatch P"X" * S"XX"
@test_throws DimensionMismatch P"X" * S"XX"

@test_throws ArgumentError one(typeof(T"X"), 1, basis=:U)
@test_throws ArgumentError one(typeof(T"X"), 1, basis=:U)

for gt in subtypes(QuantumClifford.AbstractSingleQubitOperator)
gt == SingleQubitOperator && continue
@test_throws ArgumentError gt(0)
@test_throws ArgumentError gt(-1)
end
@test_throws ArgumentError SparseGate(random_clifford(2), [1, 2, 3])
@test_throws ArgumentError apply!(random_stabilizer(2), SparseGate(random_clifford(3), [1, 2, 3]))

for gt in subtypes(QuantumClifford.AbstractTwoQubitOperator)
@test_throws ArgumentError gt(0,1)
@test_throws ArgumentError gt(-1,1)
@test_throws ArgumentError gt(2,2)
end
for gt in subtypes(QuantumClifford.AbstractSingleQubitOperator)
gt == SingleQubitOperator && continue
@test_throws ArgumentError gt(0)
@test_throws ArgumentError gt(-1)
end

for gt in subtypes(QuantumClifford.AbstractTwoQubitOperator)
@test_throws ArgumentError gt(0,1)
@test_throws ArgumentError gt(-1,1)
@test_throws ArgumentError gt(2,2)
end

for m in [sMX,sMZ,sMY,sMRX,sMRZ,sMRY]
@test_throws ArgumentError m(0)
@test_throws ArgumentError m(-1)
@test_throws ArgumentError m(0,1)
@test_throws ArgumentError m(-1,0)
end

@test_throws DimensionMismatch Stabilizer(fill(0x0, 2), Matrix{Bool}([1 0 1;1 1 1; 1 0 1]), Matrix{Bool}([1 0 0;1 1 1;1 0 1]))
@test_throws DimensionMismatch Stabilizer(fill(0x0, 2), Matrix{Bool}([1 0 1 1 0 0; 1 1 1 1 1 1; 1 0 1 1 0 1]))

for m in [sMX,sMZ,sMY,sMRX,sMRZ,sMRY]
@test_throws ArgumentError m(0)
@test_throws ArgumentError m(-1)
@test_throws ArgumentError m(0,1)
@test_throws ArgumentError m(-1,0)
end
end

0 comments on commit 393bbfc

Please sign in to comment.