Skip to content

Commit

Permalink
add iterative bitflip decoder (QuantumSavory#255)
Browse files Browse the repository at this point in the history
  • Loading branch information
Krastanov authored Apr 9, 2024
1 parent 9a36302 commit 4a007f9
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 28 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.3 - 2024-04-08

- The ECC module now has access to an iterative bitflip decoder thanks to `LDPCDecoders.jl`.

## v0.9.2 - 2024-04-02

- Provide more configuration options in the `PyBeliefProp` decoders.
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.2"
version = "0.9.3"

[deps]
Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,56 +6,87 @@ using QuantumClifford
using QuantumClifford.ECC
import QuantumClifford.ECC: AbstractSyndromeDecoder, decode, parity_checks

struct BeliefPropDecoder <: AbstractSyndromeDecoder
"""Stabilizer tableau defining the code"""
struct BeliefPropDecoder <: AbstractSyndromeDecoder # TODO all these decoders have the same fields, maybe we can factor out a common type
H
"""Faults matrix corresponding to the code"""
faults_matrix
"""The number of qubits in the code"""
n
"""The depth of the code"""
s
"""The number of encoded qubits"""
k
"""Number of X checks"""
cx
"""Number of X checks"""
cz
"""The classical BP decoder for Hx"""
bpdecoderx
"""The classical BP decoder for Hz"""
bpdecoderz
end

function BeliefPropDecoder(c, p_init=0, max_iters=10)
struct BitFlipDecoder <: AbstractSyndromeDecoder # TODO all these decoders have the same fields, maybe we can factor out a common type
H
faults_matrix
n
s
k
cx
cz
bfdecoderx
bfdecoderz
end

function BeliefPropDecoder(c; errorrate=nothing, maxiter=nothing)
Hx = parity_checks_x(c)
Hz = parity_checks_z(c)
H = parity_checks(c)
s, n = size(H)
_, _, r = canonicalize!(Base.copy(H), ranks=true)
k = n - r
cx = size(Hx, 1)
cz = size(Hx, 1)
cz = size(Hz, 1)
fm = faults_matrix(H)

bpx = LDPCDecoders.BeliefPropagationDecoder(Hx, p_init, max_iters)
bpz = LDPCDecoders.BeliefPropagationDecoder(Hz, p_init, max_iters)
isnothing(errorrate) || 0errorrate1 || error(lazy"BeliefPropDecoder got an invalid error rate argument. `errorrate` must be in the range [0, 1].")
errorrate = isnothing(errorrate) ? 0.0 : errorrate
maxiter = isnothing(maxiter) ? n : maxiter
bpx = LDPCDecoders.BeliefPropagationDecoder(Hx, errorrate, maxiter)
bpz = LDPCDecoders.BeliefPropagationDecoder(Hz, errorrate, maxiter)

return BeliefPropDecoder(H, fm, n, s, k, cx, cz, bpx, bpz)
end

function BitFlipDecoder(c; errorrate=nothing, maxiter=nothing)
Hx = parity_checks_x(c)
Hz = parity_checks_z(c)
H = parity_checks(c)
s, n = size(H)
_, _, r = canonicalize!(Base.copy(H), ranks=true)
k = n - r
cx = size(Hx, 1)
cz = size(Hz, 1)
fm = faults_matrix(H)

isnothing(errorrate) || 0errorrate1 || error(lazy"BitFlipDecoder got an invalid error rate argument. `errorrate` must be in the range [0, 1].")
errorrate = isnothing(errorrate) ? 0.0 : errorrate
maxiter = isnothing(maxiter) ? n : maxiter
bfx = LDPCDecoders.BitFlipDecoder(Hx, errorrate, maxiter)
bfz = LDPCDecoders.BitFlipDecoder(Hz, errorrate, maxiter)

return BitFlipDecoder(H, fm, n, s, k, cx, cz, bfx, bfz)
end

parity_checks(d::BeliefPropDecoder) = d.H
parity_checks(d::BitFlipDecoder) = d.H

function decode(d::BeliefPropDecoder, syndrome_sample)
row_x = syndrome_sample[1:d.cx]
row_z = syndrome_sample[d.cx+1:d.cx+d.cz]
guess_z, success = LDPCDecoders.decode!(d.bpdecoderx, row_x)
guess_x, success = LDPCDecoders.decode!(d.bpdecoderz, row_z)
return vcat(guess_x, guess_z)
end

guess_x = falses(d.n)
guess_z = falses(d.n)

success = LDPCDecoders.decode!(d.bpx, row_x, guess_x)
success = LDPCDecoders.decode!(d.bpz, row_z, guess_z)
return vcat(guess_z, guess_x)
function decode(d::BitFlipDecoder, syndrome_sample)
row_x = syndrome_sample[1:d.cx]
row_z = syndrome_sample[d.cx+1:d.cx+d.cz]
guess_z, success = LDPCDecoders.decode!(d.bfdecoderx, row_x)
guess_x, success = LDPCDecoders.decode!(d.bfdecoderz, row_z)
return vcat(guess_x, guess_z)
end

end
17 changes: 11 additions & 6 deletions ext/QuantumCliffordPyQDecodersExt/QuantumCliffordPyQDecodersExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import QuantumClifford.ECC: AbstractSyndromeDecoder, decode, batchdecode, parity

abstract type PyBP <: AbstractSyndromeDecoder end

struct PyBeliefPropDecoder <: PyBP
struct PyBeliefPropDecoder <: PyBP # TODO all these decoders have the same fields, maybe we can factor out a common type
code
H
Hx
Expand All @@ -20,7 +20,7 @@ struct PyBeliefPropDecoder <: PyBP
pyz
end

struct PyBeliefPropOSDecoder <: PyBP
struct PyBeliefPropOSDecoder <: PyBP # TODO all these decoders have the same fields, maybe we can factor out a common type
code
H
Hx
Expand All @@ -47,7 +47,7 @@ function PyBeliefPropDecoder(c; maxiter=nothing, bpmethod=nothing, errorrate=not
return PyBeliefPropDecoder(c, H, Hx, Hz, size(Hx, 1), size(Hz, 1), fm, pyx, pyz)
end

function PyBeliefPropOSDecoder(c; maxiter=nothing, bpmethod=nothing, errorrate=nothing)
function PyBeliefPropOSDecoder(c; maxiter=nothing, bpmethod=nothing, errorrate=nothing, osdmethod=nothing, osdorder=0)
Hx = parity_checks_x(c) |> collect # TODO should be sparse
Hz = parity_checks_z(c) |> collect # TODO should be sparse
H = parity_checks(c)
Expand All @@ -57,8 +57,12 @@ function PyBeliefPropOSDecoder(c; maxiter=nothing, bpmethod=nothing, errorrate=n
bp_method = get(Dict(:productsum => 0, :minsum => 1, :minsumlog => 2), bpmethod, 0)
isnothing(errorrate) || 0errorrate1 || error(lazy"PyBeliefPropDecoder got an invalid error rate argument. `errorrate` must be in the range [0, 1].")
error_rate = isnothing(errorrate) ? PythonCall.Py(nothing) : errorrate
pyx = ldpc.bposd_decoder(np.array(Hx); max_iter, bp_method, error_rate) # TODO should be sparse
pyz = ldpc.bposd_decoder(np.array(Hz); max_iter, bp_method, error_rate) # TODO should be sparse
isnothing(osdmethod) || osdmethod (:zeroorder, :exhaustive, :combinationsweep) || error(lazy"PyBeliefPropOSDecoder got an unknown OSD method argument. `osdmethod` must be one of :zeroorder, :exhaustive, :combinationsweep.")
osd_method = get(Dict(:zeroorder => "osd0", :exhaustive => "osde", :combinationsweep => "osdcs"), osdmethod, 0)
0osdorder || error(lazy"PyBeliefPropOSDecoder got an invalid OSD order argument. `osdorder` must be ≥0.")
osd_order = osdorder
pyx = ldpc.bposd_decoder(np.array(Hx); max_iter, bp_method, error_rate, osd_method, osd_order) # TODO should be sparse
pyz = ldpc.bposd_decoder(np.array(Hz); max_iter, bp_method, error_rate, osd_method, osd_order) # TODO should be sparse
return PyBeliefPropOSDecoder(c, H, Hx, Hz, size(Hx, 1), size(Hz, 1), fm, pyx, pyz)
end

Expand All @@ -67,12 +71,13 @@ parity_checks(d::PyBP) = d.H
function decode(d::PyBP, syndrome_sample)
row_x = syndrome_sample[1:d.nx] # TODO These copies and indirections might be costly!
row_z = syndrome_sample[d.nx+1:end]
@show (size(row_x), size(row_z))
guess_z_errors = PythonCall.PyArray(d.pyx.decode(np.array(row_x)))
guess_x_errors = PythonCall.PyArray(d.pyz.decode(np.array(row_z)))
vcat(guess_x_errors, guess_z_errors)
end

struct PyMatchingDecoder <: AbstractSyndromeDecoder
struct PyMatchingDecoder <: AbstractSyndromeDecoder # TODO all these decoders have the same fields, maybe we can factor out a common type
code
H
Hx
Expand Down
2 changes: 1 addition & 1 deletion src/ecc/ECC.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export parity_checks, parity_checks_x, parity_checks_z, iscss,
evaluate_decoder,
CommutationCheckECCSetup, NaiveSyndromeECCSetup, ShorSyndromeECCSetup,
TableDecoder,
BeliefPropDecoder,
BeliefPropDecoder, BitFlipDecoder,
PyBeliefPropDecoder, PyBeliefPropOSDecoder, PyMatchingDecoder

"""Parity check tableau of a code.
Expand Down
10 changes: 10 additions & 0 deletions src/ecc/decoder_pipeline.jl
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,16 @@ function BeliefPropDecoder(args...; kwargs...)
return ext.BeliefPropDecoder(args...; kwargs...)
end

"""An Iterative Bitflip decoder built around tools from `LDPCDecoders.jl`."""
function BitFlipDecoder(args...; kwargs...)
ext = Base.get_extension(QuantumClifford, :QuantumCliffordLDPCDecodersExt)
if isnothing(ext)
throw("The `BitFlipDecoder` depends on the package `LDPCDecoders` but you have not installed or imported `LDPCDecoders` yet. Immediately after you import `LDPCDecoders`, the `BitFlipDecoder` will be available.")
end
return ext.BitFlipDecoder(args...; kwargs...)
end


"""A Belief Propagation decoder built around tools from the python package `ldpc` available from the julia package `PyQDecoders.jl`."""
function PyBeliefPropDecoder(args...; kwargs...)
ext = Base.get_extension(QuantumClifford, :QuantumCliffordPyQDecodersExt)
Expand Down

0 comments on commit 4a007f9

Please sign in to comment.