Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ These changes affect internal implementation details - external packages should

- `permutesystems` and `permutesystems!` are no implemented, deprecating `permute` and `permute!`

## Added
- BP-OTS (Belief Propagation with Oscillating Trapping Sets) decoder for quantum LDPC codes in the LDPCDecoders extension

## v0.9.18 - 2025-02-19

- Fixes for rare crashes in the python BP decoders.
Expand Down
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ ILog2 = "0.2.3, 1, 2"
InteractiveUtils = "1.10"
JuMP = "1.23"
KernelAbstractions = "0.9.35"
LDPCDecoders = "0.3.2"
LDPCDecoders = "0.3.3"
LinearAlgebra = "1.10"
MacroTools = "0.5.9"
Makie = "0.20, 0.21, 0.22, 0.23, 0.24"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,88 @@ struct BitFlipDecoder <: AbstractSyndromeDecoder # TODO all these decoders have
bfdecoderz
end

"""
BPOTSDecoder(code; errorrate=nothing, maxiter=nothing, T=9, C=2.0)

BP-OTS (Belief Propagation with Oscillating Trapping Sets) decoder for quantum LDPC codes.
This decoder uses oscillation tracking and biasing to escape trapping sets.

# Arguments
- `code`: A quantum code (e.g., Toric, Surface)
- `errorrate`: Physical error rate (depolarizing probability)
- `maxiter`: Maximum number of iterations (default: 200)
- `T`: Biasing period (default: 9)
- `C`: Bias constant (default: 2.0)

# Reference
Chytas et al., "Enhanced Message-Passing Decoding of Degenerate Quantum Codes
Utilizing Trapping Set Dynamics", IEEE Communications Letters, 2024
"""
struct BPOTSDecoder <: AbstractSyndromeDecoder
original_code
H::SparseMatrixCSC{Bool,Int}
faults_matrix::Matrix{Bool}
n::Int
s::Int
k::Int
cx::Int
cz::Int
bpots_x::LDPCDecoders.BPOTSDecoder
bpots_z::LDPCDecoders.BPOTSDecoder
end

function BPOTSDecoder(c; errorrate=nothing, maxiter=nothing, T=9, C=2.0)

Hx_raw = parity_checks_x(c)
Hz_raw = parity_checks_z(c)
H_raw = parity_checks(c)

if H_raw isa Stabilizer
H_gf2 = stab_to_gf2(H_raw)
H = sparse(Bool.(H_gf2))
else
H = sparse(Bool.(H_raw))
end

if Hx_raw isa Stabilizer
Hx_gf2 = stab_to_gf2(Hx_raw)
Hz_gf2 = stab_to_gf2(Hz_raw)
Hx = sparse(Bool.(Hx_gf2))
Hz = sparse(Bool.(Hz_gf2))
else
Hx = sparse(Bool.(Hx_raw))
Hz = sparse(Bool.(Hz_raw))
end

s, n = size(H)
k = code_k(c)

cx = size(Hx, 1)
cz = size(Hz, 1)

fm = BitMatrix(ones(Bool, s, 2*n))

errorrate = something(errorrate, 0.0)
maxiter = something(maxiter, 200)
bpots_x = LDPCDecoders.BPOTSDecoder(Hx, errorrate, maxiter; T=T, C=C)
bpots_z = LDPCDecoders.BPOTSDecoder(Hz, errorrate, maxiter; T=T, C=C)

return BPOTSDecoder(c, H, fm, n, s, k, cx, cz, bpots_x, bpots_z)
end

function decode(d::BPOTSDecoder, syndrome_sample::AbstractVector{Bool})
length(syndrome_sample) == d.cx + d.cz ||
throw(DimensionMismatch("Syndrome length ($(length(syndrome_sample))) does not match expected size ($(d.cx + d.cz))"))

row_x = @view syndrome_sample[1:d.cx]
row_z = @view syndrome_sample[d.cx+1:d.cx+d.cz]

guess_z, conv_z = LDPCDecoders.decode!(d.bpots_x, Vector(row_x))
guess_x, conv_x = LDPCDecoders.decode!(d.bpots_z, Vector(row_z))

return vcat(guess_x, guess_z)
end

function BeliefPropDecoder(c; errorrate=nothing, maxiter=nothing)
Hx = parity_matrix_x(c)
Hz = parity_matrix_z(c)
Expand Down Expand Up @@ -73,6 +155,7 @@ end

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

function decode(d::BeliefPropDecoder, syndrome_sample)
row_x = @view syndrome_sample[1:d.cx]
Expand Down
2 changes: 1 addition & 1 deletion src/ecc/ECC.jl
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export parity_checks, parity_matrix_x, parity_matrix_z, iscss,
evaluate_decoder,
CommutationCheckECCSetup, NaiveSyndromeECCSetup, ShorSyndromeECCSetup,
TableDecoder,
BeliefPropDecoder, BitFlipDecoder,
BeliefPropDecoder, BitFlipDecoder, BPOTSDecoder,
PyBeliefPropDecoder, PyBeliefPropOSDecoder, PyMatchingDecoder, DecoderCorrectionGate

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

"""A BP-OTS (Belief Propagation with Oscillating Trapping Sets) decoder built around tools from `LDPCDecoders.jl`.
"""
function BPOTSDecoder(args...; kwargs...)
ext = Base.get_extension(QuantumClifford, :QuantumCliffordLDPCDecodersExt)
if isnothing(ext)
throw("The `BPOTSDecoder` depends on the package `LDPCDecoders` but you have not installed or imported `LDPCDecoders` yet. Immediately after you import `LDPCDecoders`, the `BPOTSDecoder` will be available.")
end
return ext.BPOTSDecoder(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...)
Expand Down
30 changes: 30 additions & 0 deletions test/test_ecc_decoder_all_setups.jl
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,36 @@
end
end

##
@testset "BPOTSDecoder decoder, good for topological codes" begin
codes = [
Toric(6,6),
Toric(8,8),
Surface(6,6),
Surface(8,8)
]

noise = 0.01

setups = [
CommutationCheckECCSetup(noise),
NaiveSyndromeECCSetup(noise, 0),
ShorSyndromeECCSetup(noise, 0),
]

for c in codes
for s in setups
for d in [c->BPOTSDecoder(c, errorrate=noise, maxiter=200, T=9, C=2.0)]
e = evaluate_decoder(d(c), s, 10000)
#@show c
#@show s
#@show e
@test max(e...) < noise/2
end
end
end
end

##

using Test
Expand Down
Loading