diff --git a/docs/src/references.bib b/docs/src/references.bib index 1cbde2910..31ab5aa90 100644 --- a/docs/src/references.bib +++ b/docs/src/references.bib @@ -454,3 +454,21 @@ @article{raveendran2022finite issn = {2521-327X}, doi = {10.22331/q-2022-07-20-767}, } + +@article{bravyi2024high, + title={High-threshold and low-overhead fault-tolerant quantum memory}, + author={Bravyi, Sergey and Cross, Andrew W and Gambetta, Jay M and Maslov, Dmitri and Rall, Patrick and Yoder, Theodore J}, + journal={Nature}, + volume={627}, + number={8005}, + pages={778--782}, + year={2024}, + publisher={Nature Publishing Group UK London} +} + +@article{berthusen2024toward, + title={Toward a 2D local implementation of quantum LDPC codes}, + author={Berthusen, Noah and Devulapalli, Dhruv and Schoute, Eddie and Childs, Andrew M and Gullans, Michael J and Gorshkov, Alexey V and Gottesman, Daniel}, + journal={arXiv preprint arXiv:2404.17676}, + year={2024} +} diff --git a/docs/src/references.md b/docs/src/references.md index b37e94d4e..eac3a30a5 100644 --- a/docs/src/references.md +++ b/docs/src/references.md @@ -37,6 +37,7 @@ For quantum code construction routines: - [kitaev2003fault](@cite) - [fowler2012surface](@cite) - [knill1996concatenated](@cite) +- [bravyi2024high](@cite) For classical code construction routines: - [muller1954application](@cite) diff --git a/src/ecc/ECC.jl b/src/ecc/ECC.jl index d8e863136..8f273d4a2 100644 --- a/src/ecc/ECC.jl +++ b/src/ecc/ECC.jl @@ -9,7 +9,7 @@ using DocStringExtensions using Combinatorics: combinations using SparseArrays: sparse using Statistics: std -using Nemo: ZZ, residue_ring, matrix, finite_field, GF, minpoly, coeff, lcm, FqPolyRingElem, FqFieldElem, is_zero, degree, defining_polynomial, is_irreducible, echelon_form +using Nemo: ZZ, residue_ring, matrix, finite_field, GF, minpoly, coeff, lcm, FqPolyRingElem, FqFieldElem, is_zero, degree, defining_polynomial, is_irreducible, echelon_form, nullspace, hom, free_module, kernel, domain, map, gens abstract type AbstractECC end @@ -376,7 +376,6 @@ include("codes/gottesman.jl") include("codes/surface.jl") include("codes/concat.jl") include("codes/random_circuit.jl") - include("codes/classical/reedmuller.jl") include("codes/classical/recursivereedmuller.jl") include("codes/classical/bch.jl") @@ -384,5 +383,6 @@ include("codes/classical/bch.jl") # qLDPC include("codes/classical/lifted.jl") include("codes/lifted_product.jl") +include("codes/bbqldpc.jl") end #module diff --git a/src/ecc/codes/bbqldpc.jl b/src/ecc/codes/bbqldpc.jl new file mode 100644 index 000000000..ecbed1c68 --- /dev/null +++ b/src/ecc/codes/bbqldpc.jl @@ -0,0 +1,53 @@ +""" +A bivariate bicycle (BB) quantum LDPC code was introduced by Bravyi et al. in their 2024 paper [bravyi2024high](@cite). This code uses identity and cyclic shift matrices. Define `Iₗ` as the `l × l` identity matrix and `Sₗ` as the cyclic shift matrix of the same size, where each row of `Sₗ` has a single '1' at the column `(i + 1) mod l`. + +The matrices `x = Sₗ ⊗ Iₘ` and `y = Iₗ ⊗ Sₘ` are used. The BB code is represented by matrices `A` and `B`, defined as: `A = A₁ + A₂ + A₃` and `B = B₁ + B₂ + B₃`. The addition and multiplication operations on binary matrices are performed modulo 2. The check matrices are: `Hx = [A|B]` and `Hz = [B'|A']`. Both `Hx` and `Hz` are `(n/2)×n` matrices. + +The ECC Zoo has an [entry for this family](https://errorcorrectionzoo.org/c/qcga). +""" +struct BBQLDPC <: AbstractECC + l::Int + m::Int + A::Vector{Int} + B::Vector{Int} + function BBQLDPC(l,m,A,B) + (l >= 0 && m >= 0) || error("l and m must be non-negative") + (length(A) == 3 && length(B) == 3) || error("A and B must each have exactly 3 entries") + (all(x -> x >= 0, A) && all(x -> x >= 0, B)) || error("A and B must contain only non-negative integers") + new(l,m,A,B) + end +end + +function iscss(::Type{BBQLDPC}) + return true +end + +function _AB(c::BBQLDPC) + a₁,a₂,a₃ = c.A[1],c.A[2],c.A[3] + b₁,b₂,b₃ = c.B[1],c.B[2],c.B[3] + Iₗ = Matrix{Bool}(LinearAlgebra.I,c.l,c.l) + Iₘ = Matrix{Bool}(LinearAlgebra.I,c.m,c.m) + x = Dict{Bool, Matrix{Bool}}() + y = Dict{Bool, Matrix{Bool}}() + x = Dict(i => kron(circshift(Iₗ,(0,i)),Iₘ) for i in 0:(c.l)) + y = Dict(i => kron(Iₗ,circshift(Iₘ,(0,i))) for i in 0:(c.m)) + A = mod.(x[a₁]+y[a₂]+y[a₃],2) + B = mod.(y[b₁]+x[b₂]+x[b₃],2) + return A, B +end + +function parity_checks(c::BBQLDPC) + A, B = _AB(c) + Hx = hcat(A,B) + Hz = hcat(B',A') + H = CSS(Hx,Hz) + Stabilizer(H) +end + +code_n(c::BBQLDPC) = 2*c.l*c.m + +code_k(c::BBQLDPC) = code_n(c) - LinearAlgebra.rank(matrix(GF(2), parity_checks_x(c))) - LinearAlgebra.rank(matrix(GF(2), parity_checks_z(c))) + +parity_checks_x(c::BBQLDPC) = hcat(_AB(c)...) + +parity_checks_z(c::BBQLDPC) = hcat(_AB(c)[2]', _AB(c)[1]') diff --git a/test/test_ecc_bbqldpc.jl b/test/test_ecc_bbqldpc.jl new file mode 100644 index 000000000..a7d4743e0 --- /dev/null +++ b/test/test_ecc_bbqldpc.jl @@ -0,0 +1,41 @@ +@testitem "Bivariate bicycle (BB) quantum LDPC code" begin + using QuantumClifford: stab_to_gf2 + using QuantumClifford.ECC + using Nemo: nullspace, GF, matrix, hom, free_module, kernel, domain, map, gens + using QuantumClifford.ECC: AbstractECC, BBQLDPC, parity_checks_x, parity_checks_z + + # According to Lemma 1 from [bravyi2024high](@cite), k = 2·dim(ker(A)∩ker(B)). + function _formula_k(stab) + Hx = parity_checks_x(stab) + n = size(Hx,2)÷2 + A = matrix(GF(2), Hx[:,1:n]) + B = matrix(GF(2), Hx[:,n+1:end]) + k = GF(2) + hA = hom(free_module(k, size(A, 1)), free_module(k, size(A, 2)), A) + hB = hom(free_module(k, size(B, 1)), free_module(k, size(B, 2)), B) + ans = kernel(hA)[1] ∩ kernel(hB)[1] + k = 2*size(map(domain(hA), gens(ans[1])), 1) + return k + end + + @testset "Verify number of logical qubits `k` from Table 3" begin + # Refer to [bravyi2024high](@cite) for code constructions + @test code_k(BBQLDPC(9 , 6 , [3 , 1 , 2] , [3 , 1 , 2])) == 8 == _formula_k(BBQLDPC(9 , 6 , [3 , 1 , 2] , [3 , 1 , 2])) + @test code_k(BBQLDPC(15, 3 , [9 , 1 , 2] , [0 , 2 , 7])) == 8 == _formula_k(BBQLDPC(15, 3 , [9 , 1 , 2] , [0 , 2 , 7])) + @test code_k(BBQLDPC(12, 12, [3 , 2 , 7] , [3 , 1 , 2])) == 12 == _formula_k(BBQLDPC(12, 12, [3 , 2 , 7] , [3 , 1 , 2])) + @test code_k(BBQLDPC(12, 6 , [3 , 1 , 2] , [3 , 1 , 2])) == 12 == _formula_k(BBQLDPC(12, 6 , [3 , 1 , 2] , [3 , 1 , 2])) + @test code_k(BBQLDPC(6 , 6 , [3 , 1 , 2] , [3 , 1 , 2])) == 12 == _formula_k(BBQLDPC(6 , 6 , [3 , 1 , 2] , [3 , 1 , 2])) + @test code_k(BBQLDPC(30, 6 , [9 , 1 , 2] , [3 , 25, 26])) == 12 == _formula_k(BBQLDPC(30, 6 , [9 , 1 , 2] , [3 , 25, 26])) + @test code_k(BBQLDPC(21, 18, [3 , 10, 17], [5 , 3 , 19])) == 16 == _formula_k(BBQLDPC(21, 18, [3 , 10, 17], [5 , 3 , 19])) + @test code_k(BBQLDPC(28, 14, [26, 6 , 8] , [7 , 9 , 20])) == 24 == _formula_k(BBQLDPC(28, 14, [26, 6 , 8] , [7 , 9 , 20])) + end + + @testset "Verify number of logical qubits `k` from Table 1" begin + # Refer to [berthusen2024toward](cite for code constructions + @test code_k(BBQLDPC(12, 3 , [9 , 1 , 2] , [0 , 1 , 11])) == 8 == _formula_k(BBQLDPC(12, 3 , [9 , 1 , 2] , [0 , 1 , 11])) + @test code_k(BBQLDPC(9 , 5 , [8 , 4 , 1] , [5 , 8 , 7])) == 8 == _formula_k(BBQLDPC(9 , 5 , [8 , 4 , 1], [5 , 8 , 7])) + @test code_k(BBQLDPC(12, 5 , [10, 4 , 1] , [0 , 1 , 2])) == 8 == _formula_k(BBQLDPC(12, 5 , [10, 4 , 1] , [0 , 1 , 2])) + @test code_k(BBQLDPC(15, 5 , [5 , 2 , 3] , [2 , 7 , 6])) == 8 == _formula_k(BBQLDPC(15, 5 , [5 , 2 , 3] , [2 , 7 , 6])) + @test code_k(BBQLDPC(14, 7 , [6 , 5 , 6] , [0 , 4, 13])) == 12 == _formula_k(BBQLDPC(14, 7 , [6 , 5 , 6] , [0 , 4, 13])) + end +end