Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Evaluating [[23, 1, 7]] quantum Golay code with decoders - an outlook #301

Open
Fe-r-oz opened this issue Jun 29, 2024 · 2 comments
Open

Comments

@Fe-r-oz
Copy link
Contributor

Fe-r-oz commented Jun 29, 2024

The [[23, 1, 7]] quantum Golay code

I was exploring the [[23, 1, 7]] quantum Golay code after implementation, I wanted to check how it gets evaluated by the decoders before submitting it for review.

Please have a look at these graphs (attached below), I am not sure that these graphs are good, Please have a look, @Krastanov, Thanks.

Quantum Golay code is used by this recent 2024 paper: Code conversion with the quantum Golay code for a universal transversal gate set

Followed this paper: Fault-tolerant ancilla preparation and noise threshold lower bounds for the 23-qubit Golay code

Construction Method

"""
The[ paper](https://arxiv.org/pdf/1106.2190) describes that the code is self-dual, and the X and Z stabilizer generators can both be given by the following eleven 23-character strings:

. 1 . . 1 . . 1 1 1 1 1 . . . . . . . . . . 1
1 . . 1 . . 1 1 1 1 1 . . . . . . . . . . 1 .
. 1 1 . 1 1 1 . . . 1 1 . . . . . . . . 1 . .
1 1 . 1 1 1 . . . 1 1 . . . . . . . . 1 . . .
1 1 1 1 . . . 1 . . 1 1 . . . . . . 1 . . . .
1 . 1 . 1 . 1 1 1 . . 1 . . . . . 1 . . . . .
. . . 1 1 1 1 . 1 1 . 1 . . . . 1 . . . . . .
. . 1 1 1 1 . 1 1 . 1 . . . . 1 . . . . . . .
. 1 1 1 1 . 1 1 . 1 . . . . 1 . . . . . . . .
1 1 1 1 . 1 1 . 1 . . . . 1 . . . . . . . . .
1 . 1 . . 1 . . 1 1 1 1 1 . . . . . . . . . .
Here, the 1s in a row either all indicate Z operators or all indicate X operators, and dots indicate I operators.
"""

I went with one that takes 65 gates which is least expensive. The paper implements them with 57 CNOTs.
struct QuantumGolay <: AbstractECC end

code_n(c::QuantumGolay) = 23
code_k(c::QuantumGolay) = 1
distance(c::QuantumGolay) = 7

function iscss(::Type{QuantumGolay})
    return true
end

parity_checks(c::QuantumGolay) = S"X_X__X__XXXXX__________
                                   XXXX_XX_X____X_________
                                   _XXXX_XX_X____X________
                                   __XXXX_XX_X____X_______
                                   ___XXXX_XX_X____X______
                                   Z_Z_Z_ZZZ__Z_____Z_____
                                   ZZZZ___Z__ZZ______Z____
                                   ZZ_ZZZ___ZZ________Z___
                                   _ZZ_ZZZ___ZZ________Z__
                                   Z__Z__ZZZZZ__________Z_
                                   _Z__Z__ZZZZZ__________Z"


parity_checks_x(c::QuantumGolay) = stab_to_gf2(parity_checks(QuantumGolay()))[1:end-6, 1:end÷2]

parity_checks_z(c::QuantumGolay) = stab_to_gf2(parity_checks(QuantumGolay()))[end-5:end, end÷2+1:end]

I tested other combinations but it seems that the least expensive is with 65 gates.


julia> naive_encoding_circuit(parity_checks(QuantumGolay()))
65-element Vector{QuantumClifford.AbstractOperation}:
 sCNOT(12,6)
 sCNOT(12,7)
 sCNOT(12,11)
 sCNOT(18,6)
 sCNOT(18,8)
 sCNOT(18,11)
 sCNOT(19,8)
 sCNOT(19,9)
 sCNOT(20,6)
 sCNOT(20,8)
 sCNOT(20,9)
 sCNOT(20,10)
 sCNOT(20,11)
 sCNOT(21,8)
 sCNOT(21,9)
 sCNOT(21,10)
 sCNOT(21,11)
 ⋮
 sZCX(3,17)
 sHadamard(4)
 sZCX(4,6)
 sZCX(4,9)
 sZCX(4,12)
 sZCX(4,13)
 sZCX(4,14)
 sZCX(4,15)
 sZCX(4,16)
 sHadamard(5)
 sZCX(5,7)
 sZCX(5,10)
 sZCX(5,13)
 sZCX(5,14)
 sZCX(5,15)
 sZCX(5,16)
 sZCX(5,17)


parity_checks(c::QuantumGolay)  =  S"X_X__X__XXXXX__________
                                   XXXX_XX_X____X_________
                                   _XXXX_XX_X____X________
                                   __XXXX_XX_X____X_______
                                   ___ZZZZ_ZZ_Z____Z______
                                   Z_Z_Z_ZZZ__Z_____Z_____
                                   ZZZZ___Z__ZZ______Z____
                                   ZZ_ZZZ___ZZ________Z___
                                   _ZZ_ZZZ___ZZ________Z__
                                   Z__Z__ZZZZZ__________Z_
                                   _Z__Z__ZZZZZ__________Z"

julia> naive_encoding_circuit(s9)
68-element Vector{QuantumClifford.AbstractOperation}:
 sCNOT(12,5)
 sCNOT(12,6)
 sCNOT(12,10)
 sCNOT(12,11)
 sCNOT(17,5)
 sCNOT(17,7)
 sCNOT(17,10)
 sCNOT(18,5)
 sCNOT(18,6)
 sCNOT(18,7)
 sCNOT(18,8)
 sCNOT(18,10)
 sCNOT(18,11)
 sCNOT(19,5)
 sCNOT(19,7)
 sCNOT(19,8)
 sCNOT(19,9)
 ⋮
 sZCX(2,16)
 sHadamard(3)
 sZCX(3,5)
 sZCX(3,8)
 sZCX(3,11)
 sZCX(3,12)
 sZCX(3,13)
 sZCX(3,14)
 sZCX(3,15)
 sHadamard(4)
 sZCX(4,6)
 sZCX(4,9)
 sZCX(4,12)
 sZCX(4,13)
 sZCX(4,14)
 sZCX(4,15)
 sZCX(4,16)

Evaluating with Decoders

using QuantumClifford
using QuantumClifford.ECC

mem_errors = 0.001:0.0005:0.01
codes = [QuantumGolay()]
results = zeros(length(codes), length(mem_errors), 2)

for (ic, c) in pairs(codes)
    for (i,m) in pairs(mem_errors)
        setup = CommutationCheckECCSetup(m)
        decoder = TableDecoder(c)
        r = evaluate_decoder(decoder, setup, 10000)
        results[ic,i,:] .= r
    end
end

make_decoder_figure(mem_errors, results, "[[23, 1, 7]]'s code with a lookup table decoder")

display

import PyQDecoders

mem_errors = 0.001:0.005:0.1
codes = [QuantumGolay()]
results = zeros(length(codes), length(mem_errors), 2)

for (ic, c) in pairs(codes)
    for (i,m) in pairs(mem_errors)
        setup = NaiveSyndromeECCSetup(m, 0)
        decoder = BeliefPropDecoder(c)
        r = evaluate_decoder(decoder, setup, 1000)
        results[ic,i,:] .= r
    end
end

make_decoder_figure(mem_errors, results, "[[23, 1, 7]] code with a BeliefPropDecoder decoder")

display

import PyQDecoders

mem_errors = 0.00001:0.00005:0.1
codes = [QuantumGolay()]
results = zeros(length(codes), length(mem_errors), 2)

for (ic, c) in pairs(codes)
    for (i,m) in pairs(mem_errors)
        setup = CommutationCheckECCSetup(m)
        decoder = BeliefPropDecoder(c)
        r = evaluate_decoder(decoder, setup, 1000)
        results[ic,i,:] .= r
    end
end

make_decoder_figure(mem_errors, results, "[[23, 1, 7]] code with a BeliefPropDecoder decoder with CommutationCheckECCSetup")

display

With More samples:
display

I get error with PyMatching Decoder:

import PyQDecoders

mem_errors = 0.00001:0.00005:0.1
codes = [QuantumGolay()]
results = zeros(length(codes), length(mem_errors), 2)

for (ic, c) in pairs(codes)
    for (i,m) in pairs(mem_errors)
        setup = CommutationCheckECCSetup(m)
        decoder = PyMatchingDecoder(c)
        r = evaluate_decoder(decoder, setup, 1000)
        results[ic,i,:] .= r
    end
end

make_decoder_figure(mem_errors, results, "[[23, 1, 7]] code with a PyMatchingDecoder decoder with CommutationCheckECCSetup")
ERROR: Python: ValueError: `check_matrix` must contain at most two ones per column, but column 2 has 4 ones.
Python stacktrace:
 [1] load_from_check_matrix
   @ pymatching.matching ~/.julia/environments/v1.10/.CondaPkg/env/lib/python3.12/site-packages/pymatching/matching.py:1184
 [2] from_check_matrix
   @ pymatching.matching ~/.julia/environments/v1.10/.CondaPkg/env/lib/python3.12/site-packages/pymatching/matching.py:992
Stacktrace:
  [1] pythrow()
    @ PythonCall.Core ~/.julia/packages/PythonCall/bb3ax/src/Core/err.jl:92
  [2] errcheck
    @ ~/.julia/packages/PythonCall/bb3ax/src/Core/err.jl:10 [inlined]
  [3] pycallargs
    @ ~/.julia/packages/PythonCall/bb3ax/src/Core/builtins.jl:212 [inlined]
  [4] pycall(f::PythonCall.Core.Py, args::Matrix{Bool}; kwargs::@Kwargs{})
    @ PythonCall.Core ~/.julia/packages/PythonCall/bb3ax/src/Core/builtins.jl:230
  [5] pycall
    @ ~/.julia/packages/PythonCall/bb3ax/src/Core/builtins.jl:220 [inlined]
  [6] Py
    @ ~/.julia/packages/PythonCall/bb3ax/src/Core/Py.jl:339 [inlined]
  [7] QuantumCliffordPyQDecodersExt.PyMatchingDecoder(c::QuantumGolay; weights::Nothing)
    @ QuantumCliffordPyQDecodersExt ~/Desktop/New/golay/QuantumClifford.jl/ext/QuantumCliffordPyQDecodersExt/QuantumCliffordPyQDecodersExt.jl:97
  [8] QuantumCliffordPyQDecodersExt.PyMatchingDecoder(c::QuantumGolay)
    @ QuantumCliffordPyQDecodersExt ~/Desktop/New/golay/QuantumClifford.jl/ext/QuantumCliffordPyQDecodersExt/QuantumCliffordPyQDecodersExt.jl:91
  [9] PyMatchingDecoder(args::QuantumGolay; kwargs::@Kwargs{})
    @ QuantumClifford.ECC ~/Desktop/New/golay/QuantumClifford.jl/src/ecc/decoder_pipeline.jl:306
 [10] PyMatchingDecoder(args::QuantumGolay)
    @ QuantumClifford.ECC ~/Desktop/New/golay/QuantumClifford.jl/src/ecc/decoder_pipeline.jl:301

Maybe pymatching decoder should not be used with this quantum code ?

Preskill note comments -- "This code is not the most efficient quantum code that can correct three errors (there is a [17, 1, 7] code that saturates the Rains bound), but it has especially nice properties that are conducive to fault-tolerant quantum computation. From the perspective of pure mathematics, the most important error-correcting code (classical or quantum) ever discovered is also one of the first ever described in a published article — the Golay code :)"

@Krastanov
Copy link
Member

Indeed, as the error message describes, pymatching can not be used for a code like this.

The bad performance of the table decoder is pretty suspicious. One thing that can be done to check whether there is an error in implementing this is to parameterize the table decoder so that it can correct up to some constant m errors (currently it is fixed to m=1)

@Fe-r-oz
Copy link
Contributor Author

Fe-r-oz commented Jun 29, 2024

P.S. A small additional comment that may not be directly related but provides a further detail about two equivalent notations used in papers related to these codes.

These two forms of representing H matrix for this [[23, 1, 7]] quantum code are canonically equivalent:

Ben's dissertation, 2001: Error-detection-based quantum fault tolerance against discrete Pauli noise

1 . 1 . . 1 . . 1 1 1 1 1 . . . . . . . . . .
1 1 1 1 . 1 1 . 1 . . . . 1 . . . . . . . . .
. 1 1 1 1 . 1 1 . 1 . . . . 1 . . . . . . . .
. . 1 1 1 1 . 1 1 . 1 . . . . 1 . . . . . . .
. . . 1 1 1 1 . 1 1 . 1 . . . . 1 . . . . . .
1 . 1 . 1 . 1 1 1 . . 1 . . . . . 1 . . . . .
1 1 1 1 . . . 1 . . 1 1 . . . . . . 1 . . . .
1 1 . 1 1 1 . . . 1 1 . . . . . . . . 1 . . .
. 1 1 . 1 1 1 . . . 1 1 . . . . . . . . 1 . .
1 . . 1 . . 1 1 1 1 1 . . . . . . . . . . 1 .
. 1 . . 1 . . 1 1 1 1 1 . . . . . . . . . . 1

2013's paper: Fault-tolerant ancilla preparation and noise threshold lower bounds for the 23-qubit Golay code

. 1 . . 1 . . 1 1 1 1 1 . . . . . . . . . . 1
1 . . 1 . . 1 1 1 1 1 .  . . . . . . . . . 1.
. 1 1 . 1 1 1 . . . 1 1 . . . . . . . . 1 . .
1 1 . 1 1 1 . . . 1 1 . . . . . . . . 1 . . .
1 1 1 1 . . . 1 . . 1 1 . . . . . . 1 . . . .
1 . 1 . 1 . 1 1 1 . . 1 . . . . . 1 . . . . .
. . . 1 1 1 1 . 1 1 . 1 . . . . 1 . . . . . .
. . 1 1 1 1 . 1 1 . 1 . . . . 1 . . . . . . .
. 1 1 1 1 . 1 1 . 1 . . . . 1 . . . . . . . .
1 1 1 1 . 1 1 . 1 . . . . 1 . . . . . . . . . 
1 . 1 . . 1 . . 1 1 1 1 1 . . . . . . . . . .
julia> ben_2001 = [0 1 0 0 1 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1;
       1 0 0 1 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 0;
       0 1 1 0 1 1 1 0 0 0 1 1 0 0 0 0 0 0 0 0 1 0 0;
       1 1 0 1 1 1 0 0 0 1 1 0 0 0 0 0 0 0 0 1 0 0 0;
       1 1 1 1 0 0 0 1 0 0 1 1 0 0 0 0 0 0 1 0 0 0 0;
       1 0 1 0 1 0 1 1 1 0 0 1 0 0 0 0 0 1 0 0 0 0 0;
       0 0 0 1 1 1 1 0 1 1 0 1 0 0 0 0 1 0 0 0 0 0 0;
       0 0 1 1 1 1 0 1 1 0 1 0 0 0 0 1 0 0 0 0 0 0 0;
       0 1 1 1 1 0 1 1 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0;
       1 1 1 1 0 1 1 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0;
       1 0 1 0 0 1 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0];

julia> paper_2013 = [1 0 1 0 0 1 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0;
       1 1 1 1 0 1 1 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0;
       0 1 1 1 1 0 1 1 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0;
       0 0 1 1 1 1 0 1 1 0 1 0 0 0 0 1 0 0 0 0 0 0 0;
       0 0 0 1 1 1 1 0 1 1 0 1 0 0 0 0 1 0 0 0 0 0 0;
       1 0 1 0 1 0 1 1 1 0 0 1 0 0 0 0 0 1 0 0 0 0 0;
       1 1 1 1 0 0 0 1 0 0 1 1 0 0 0 0 0 0 1 0 0 0 0;
       1 1 0 1 1 1 0 0 0 1 1 0 0 0 0 0 0 0 0 1 0 0 0;
       0 1 1 0 1 1 1 0 0 0 1 1 0 0 0 0 0 0 0 0 1 0 0;
       1 0 0 1 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 0;
       0 1 0 0 1 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1];
julia> echelon_form(matrix(GF(2), paper_2013)) == echelon_form(matrix(GF(2), ben_2001))
true

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants