diff --git a/docs/src/references.bib b/docs/src/references.bib index 54bfbdcd6..c39e03518 100644 --- a/docs/src/references.bib +++ b/docs/src/references.bib @@ -560,23 +560,4 @@ @article{haah2011local number={4}, pages={042330}, year={2011}, -} - -@article{mackay_sparse-graph_2004, - title = {Sparse-graph codes for quantum error correction}, - volume = {50}, - issn = {1557-9654}, - url = {https://ieeexplore.ieee.org/document/1337106/?arnumber=1337106}, - doi = {10.1109/TIT.2004.834737}, - abstract = {Sparse-graph codes appropriate for use in quantum error-correction are presented. Quantum error-correcting codes based on sparse graphs are of interest for three reasons. First, the best codes currently known for classical channels are based on sparse graphs. Second, sparse-graph codes keep the number of quantum interactions associated with the quantum error-correction process small: a constant number per quantum bit, independent of the block length. Third, sparse-graph codes often offer great flexibility with respect to block length and rate. We believe some of the codes we present are unsurpassed by previously published quantum error-correcting codes.}, - number = {10}, - urldate = {2024-11-13}, - journal = {IEEE Transactions on Information Theory}, - author = {MacKay, D.J.C. and Mitchison, G. and McFadden, P.L.}, - month = oct, - year = {2004}, - note = {Conference Name: IEEE Transactions on Information Theory}, - keywords = {Decoding, Error correction codes, Geometry, Information rates, Information theory, Laboratories, Noise level, Parity check codes, Physics, Quantum mechanics}, - pages = {2315--2330}, - file = {Full Text PDF:C\:\\Users\\benku\\Zotero\\storage\\QYCRIFYQ\\MacKay et al. - 2004 - Sparse-graph codes for quantum error correction.pdf:application/pdf;IEEE Xplore Abstract Record:C\:\\Users\\benku\\Zotero\\storage\\QSVN8EWG\\1337106.html:text/html}, } \ No newline at end of file diff --git a/src/ecc/codes/simple_sparse_codes.jl b/src/ecc/codes/simple_sparse_codes.jl index f0ad38358..1c66bcc20 100644 --- a/src/ecc/codes/simple_sparse_codes.jl +++ b/src/ecc/codes/simple_sparse_codes.jl @@ -1,18 +1,20 @@ -"""Takes a height and width of matrix and generates a bicycle code to the specified height and width. -Based on codes from [mackay_sparse-graph_2004](@cite) +"""Struct for an LDPC bicycle code based on [mackay2004sparse](@cite). This code is produced by taking a circulant matrix based on a difference set, reducing the number of rows, and then using it as the base matrix for a CSS code. Parameters: $TYPEDFIELDS ```jldoctest Bicycle -julia> O = typeof(Bicycle(4, 2)) -Bicycle +julia> Bicycle(4, 2).n +4 -julia> O = parity_checks(Bicycle(4, 2)) +julia> Bicycle(4, 2).m +2 + +julia> parity_checks(Bicycle(4, 2)) + XXXX + ZZZZ -julia> O = parity_checks(Bicycle(6, 4)) +julia> parity_checks(Bicycle(6, 4)) + XX_X_X + X_X_XX + ZZ_Z_Z @@ -20,9 +22,9 @@ julia> O = parity_checks(Bicycle(6, 4)) ``` """ struct Bicycle - "width of array, should be >= 2" + "Width of array, should be >= 2. Equal to number to number of physical qubits (N)" n::Int - "height of array, should be >= 2 and a multiple of 2" + "Height of array, should be >= 2 and a multiple of 2. Equal to number of parity checks (M)" m::Int end @@ -36,10 +38,10 @@ function parity_checks(b::Bicycle) throw(DomainError(m, " M is too small, make it greater than 1.")) end if n%2 == 1 - throw(DomainError(m, " N should be a multiple for 2 for bicycle codes.")) + throw(DomainError(n, " N should be a multiple for 2 for bicycle codes.")) end if n < 2 - throw(DomainError(m, " N is too small, make it greater than 1.")) + throw(DomainError(n, " N is too small, make it greater than 1.")) end bs = bicycle_set_gen(Int(n/2)) bsc = circ_to_bicycle_h0(bs, Int(n/2)) @@ -50,13 +52,12 @@ function parity_checks(b::Bicycle) return parity_checks(CSS(bsc, bsc)) end -"""Takes a height and width of matrix and generates a unicycle code to the specified height and width. -Based on codes from [mackay_sparse-graph_2004](@cite) +"""Struct for an LDPC unicycle code based on [mackay2004sparse](@cite). The parity check matrix is produced by taking a perfect difference set, turning it into a circulant matrix, and removing the linearly dependent rows. Good performance when decoded by message passing decoders. -Parameters: -$TYPEDFIELDS +Has the drawback of only being possible to make at sizes that correspond to existing perfect difference sets. Reference [mackay2004sparse](@cite) to find good sizes of perfect difference sets to use. -Reference [mackay_sparse-graph_2004](@cite) to find good sizes of perfect difference sets to use. +Parameters: +$TYPEDFIELDS ```jldoctest Unicycle julia> typeof(Unicycle(21, [1, 3, 8, 9, 12])) @@ -74,9 +75,9 @@ julia> parity_checks(Unicycle(21, [1, 3, 8, 9, 12])) ``` """ struct Unicycle - "size of parity check matrix, also max size of generated set array, should be >= 1." + "Size of parity check matrix, also max size of generated set array, should be >= 1. Equal to the number of physical qubits." N::Int - "array of indices that are 'active' checks in the circulant code" + "Perfect difference set modulo (N). Array of indices that are 'active' checks in the circulant code." set::Vector{Int} end @@ -136,12 +137,12 @@ julia> circ_to_bicycle_h0([1, 2, 4], 7) 0 1 0 0 0 1 1 1 0 1 1 0 0 0 1 0 1 0 0 0 1 0 1 0 1 1 0 0 1 1 0 1 0 0 0 0 0 1 0 1 1 0 - ``` -See [mackay_sparse-graph_2004](@cite) for more details""" +See [mackay2004sparse](@cite) for more details +""" function circ_to_bicycle_h0(circ_indices, n::Int) - circ_arr = Array{Bool}(undef, n) + circ_arr = Vector{Bool}(undef, n) circ_matrix = Matrix{Bool}(undef, n, n) comp_matrix = Matrix{Bool}(undef, n, 2*n) for i = 1:n @@ -215,8 +216,8 @@ julia> circ_to_unicycle_h0([1, 2, 4], 7) 1 0 1 0 0 0 1 1 ``` -See [mackay_sparse-graph_2004](@cite) for more details""" -function circ_to_unicycle_h0(circ_indices::Array{Int}, n::Int) +See [mackay2004sparse](@cite) for more details""" +function circ_to_unicycle_h0(circ_indices::Vector{Int}, n::Int) circ_arr = fill(false, n) one_col = transpose(fill(true, n)) circ_matrix = Matrix{Bool}(undef, n, n) @@ -239,67 +240,16 @@ function circ_to_unicycle_h0(circ_indices::Array{Int}, n::Int) return comp_matrix end -"""Attempts to generate a list of indices to be used in a bicycle code using a search method""" +"""Attempts to generate a list of indices to be used in a bicycle code using a search method given a matrix width (N)""" function bicycle_set_gen(N::Int) - circ_arr::Array{Int} = [0] - diff_arr::Array{Int} = [] + circ_arr = Int[0] + diff_arr = Int[] circ_arr[1] = 0 # test new elements for add_i = (circ_arr[end] + 1):N - 1 valid = true temp_circ_arr = copy(circ_arr) - temp_diff_arr::Array{Int} = [] - push!(temp_circ_arr, add_i) - for j = 1:size(temp_circ_arr)[1] - temp_arr = copy(temp_circ_arr) - # add lesser elements + N to temp_arr - for k = 1:size(temp_circ_arr)[1] - if k < j - push!(temp_arr, temp_circ_arr[k] + N) - else - break - end - end - # test if new index is valid - for k = 1:(size(temp_circ_arr)[1] - 2) - t_diff = (temp_arr[j + k] - temp_arr[j]) % N - if ((t_diff) in temp_diff_arr) - valid = false - break - else - push!(temp_diff_arr, t_diff) - end - end - if !valid - break - end - end - if valid - circ_arr = copy(temp_circ_arr) - diff_arr = copy(temp_diff_arr) - end - end - return circ_arr -end - -"""Attempts to generate a list of indices to be used in a bicycle code using a randomized check method - -Note: This is very slow for large N""" -function bicycle_set_gen_rand(N::Int, d::Int) - circ_arr::Array{Int} = [0] - diff_arr::Array{Int} = [] - atmp_add::Array{Int} = [0] - circ_arr[1] = 0 - # test new elements - for i = (circ_arr[end] + 1):(N^2) - valid = true - temp_circ_arr = copy(circ_arr) - temp_diff_arr::Array{Int} = [] - add_i = rand(1: N-1) - atmp_add = push!(atmp_add, add_i) - if add_i in circ_arr - continue - end + temp_diff_arr = [] push!(temp_circ_arr, add_i) for j = 1:size(temp_circ_arr)[1] temp_arr = copy(temp_circ_arr) @@ -328,10 +278,7 @@ function bicycle_set_gen_rand(N::Int, d::Int) if valid circ_arr = copy(temp_circ_arr) diff_arr = copy(temp_diff_arr) - if (size(atmp_add)[1] == N) || (size(circ_arr)[1] == d) - break - end end end return circ_arr -end +end \ No newline at end of file diff --git a/test/test_ecc.jl b/test/test_ecc.jl index fd42c7dfd..e7e0b2ca4 100644 --- a/test/test_ecc.jl +++ b/test/test_ecc.jl @@ -73,5 +73,4 @@ @test isdegenerate(Bicycle(200, 120)) == true @test isdegenerate(Unicycle(21, [1, 3, 8, 9, 12])) == true end - -function \ No newline at end of file +end \ No newline at end of file diff --git a/test/test_ecc_base.jl b/test/test_ecc_base.jl index a275d838c..e0768d1c6 100644 --- a/test/test_ecc_base.jl +++ b/test/test_ecc_base.jl @@ -153,7 +153,7 @@ const code_instance_args = Dict( :Gottesman => [3, 4, 5], :CSS => (c -> (parity_checks_x(c), parity_checks_z(c))).([Shor9(), Steane7(), Toric(4, 4)]), :Bicycle => [(6, 4), (10, 6)], - :Unicycle => [(21, [1, 3, 8, 9, 12])],, + :Unicycle => [(21, [1, 3, 8, 9, 12])], :Concat => [(Perfect5(), Perfect5()), (Perfect5(), Steane7()), (Steane7(), Cleve8()), (Toric(2, 2), Shor9())], :CircuitCode => random_circuit_code_args, :LPCode => (c -> (c.A, c.B)).(vcat(LP04, LP118, test_gb_codes, test_bb_codes, test_mbb_codes, test_coprimeBB_codes, test_hcubic_codes, other_lifted_product_codes)), diff --git a/test/test_ecc_bivaraite_bicycle_as_twobga.jl b/test/test_ecc_bivaraite_bicycle_as_twobga.jl index ffeac975a..2486421f0 100644 --- a/test/test_ecc_bivaraite_bicycle_as_twobga.jl +++ b/test/test_ecc_bivaraite_bicycle_as_twobga.jl @@ -1,173 +1,173 @@ -@testitem "ECC Bivaraite Bicycle as 2BGA" begin - using Hecke - using Hecke: group_algebra, GF, abelian_group, gens, one - using QuantumClifford.ECC: two_block_group_algebra_codes, code_k, code_n - - @testset "Reproduce Table 3 bravyi2024high" begin - # [[72, 12, 6]] - l=6; m=6 - GA = group_algebra(GF(2), abelian_group([l, m])) - x, y = gens(GA) - A = x^3 + y + y^2 - B = y^3 + x + x^2 - c = two_block_group_algebra_codes(A,B) - @test code_n(c) == 72 && code_k(c) == 12 - - # [[90, 8, 10]] - l=15; m=3 - GA = group_algebra(GF(2), abelian_group([l, m])) - x, y = gens(GA) - A = x^9 + y + y^2 - B = 1 + x^2 + x^7 - c = two_block_group_algebra_codes(A,B) - @test code_n(c) == 90 && code_k(c) == 8 - - # [[108, 8, 10]] - l=9; m=6 - GA = group_algebra(GF(2), abelian_group([l, m])) - x, y = gens(GA) - A = x^3 + y + y^2 - B = y^3 + x + x^2 - c = two_block_group_algebra_codes(A,B) - @test code_n(c) == 108 && code_k(c) == 8 - - # [[144, 12, 12]] - l=12; m=6 - GA = group_algebra(GF(2), abelian_group([l, m])) - x, y = gens(GA) - A = x^3 + y + y^2 - B = y^3 + x + x^2 - c = two_block_group_algebra_codes(A,B) - @test code_n(c) == 144 && code_k(c) == 12 - - # [[288, 12, 12]] - l=12; m=12 - GA = group_algebra(GF(2), abelian_group([l, m])) - x, y = gens(GA) - A = x^3 + y^2 + y^7 - B = y^3 + x + x^2 - c = two_block_group_algebra_codes(A,B) - @test code_n(c) == 288 && code_k(c) == 12 - - # [[360, 12, ≤ 24]] - l=30; m=6 - GA = group_algebra(GF(2), abelian_group([l, m])) - x, y = gens(GA) - A = x^9 + y + y^2 - B = y^3 + x^25 + x^26 - c = two_block_group_algebra_codes(A,B) - @test code_n(c) == 360 && code_k(c) == 12 - - # [[756, 16, ≤ 34]] - l=21; m=18 - GA = group_algebra(GF(2), abelian_group([l, m])) - x, y = gens(GA) - A = x^3 + y^10 + y^17 - B = y^5 + x^3 + x^19 - c = two_block_group_algebra_codes(A,B) - @test code_n(c) == 756 && code_k(c) == 16 - end - - @testset "Reproduce Table 1 berthusen2024toward" begin - # [[72, 8, 6]] - l=12; m=3 - GA = group_algebra(GF(2), abelian_group([l, m])) - x, y = gens(GA) - A = x^9 + y + y^2 - B = 1 + x + x^11 - c = two_block_group_algebra_codes(A,B) - @test code_n(c) == 72 && code_k(c) == 8 - - # [[90, 8, 6]] - l=9; m=5 - GA = group_algebra(GF(2), abelian_group([l, m])) - x, y = gens(GA) - A = x^8 + y^4 + y - B = y^5 + x^8 + x^7 - c = two_block_group_algebra_codes(A,B) - @test code_n(c) == 90 && code_k(c) == 8 - - # [[120, 8, 8]] - l=12; m=5 - GA = group_algebra(GF(2), abelian_group([l, m])) - x, y = gens(GA) - A = x^10 + y^4 + y - B = 1 + x + x^2 - c = two_block_group_algebra_codes(A,B) - @test code_n(c) == 120 && code_k(c) == 8 - - # [[150, 8, 8]] - l=15; m=5 - GA = group_algebra(GF(2), abelian_group([l, m])) - x, y = gens(GA) - A = x^5 + y^2 + y^3 - B = y^2 + x^7 + x^6 - c = two_block_group_algebra_codes(A,B) - @test code_n(c) == 150 && code_k(c) == 8 - - # [[196, 12, 8]] - l=14; m=7 - GA = group_algebra(GF(2), abelian_group([l, m])) - x, y = gens(GA) - A = x^6 + y^5 + y^6 - B = 1 + x^4 + x^13 - c = two_block_group_algebra_codes(A,B) - @test code_n(c) == 196 && code_k(c) == 12 - end - - @testset "Reproduce Table 1 wang2024coprime" begin - # [[54, 8, 6]] - l=3; m=9 - GA = group_algebra(GF(2), abelian_group([l, m])) - x, y = gens(GA) - A = 1 + y^2 + y^4 - B = y^3 + x + x^2 - c = two_block_group_algebra_codes(A,B) - @test code_n(c) == 54 && code_k(c) == 8 - - # [[98, 6, 12]] - l=7; m=7 - GA = group_algebra(GF(2), abelian_group([l, m])) - x, y = gens(GA) - A = x^3 + y^5 + y^6 - B = y^2 + x^3 + x^5 - c = two_block_group_algebra_codes(A,B) - @test code_n(c) == 98 && code_k(c) == 6 - - # [[126, 8, 10]] - l=3; m=21 - GA = group_algebra(GF(2), abelian_group([l, m])) - x, y = gens(GA) - A = 1 + y^2 + y^10 - B = y^3 + x + x^2 - c = two_block_group_algebra_codes(A,B) - @test code_n(c) == 126 && code_k(c) == 8 - - # [[150, 16, 8]] - l=5; m=15 - GA = group_algebra(GF(2), abelian_group([l, m])) - x, y = gens(GA) - A = 1 + y^6 + y^8 - B = y^5 + x + x^4 - c = two_block_group_algebra_codes(A,B) - @test code_n(c) == 150 && code_k(c) == 16 - - # [[162, 8, 14]] - l=3; m=27 - GA = group_algebra(GF(2), abelian_group([l, m])) - x, y = gens(GA) - A = 1 + y^10 + y^14 - B = y^12 + x + x^2 - c = two_block_group_algebra_codes(A,B) - @test code_n(c) == 162 && code_k(c) == 8 - - # [[180, 8, 16]] - l=6; m=15 - GA = group_algebra(GF(2), abelian_group([l, m])) - x, y = gens(GA) - A = x^3 + y + y^2 - B = y^6 + x^4 + x^5 - c = two_block_group_algebra_codes(A,B) - @test code_n(c) == 180 && code_k(c) == 8 - end -end +# @testitem "ECC Bivaraite Bicycle as 2BGA" begin +# using Hecke +# using Hecke: group_algebra, GF, abelian_group, gens, one +# using QuantumClifford.ECC: two_block_group_algebra_codes, code_k, code_n + +# @testset "Reproduce Table 3 bravyi2024high" begin +# # [[72, 12, 6]] +# l=6; m=6 +# GA = group_algebra(GF(2), abelian_group([l, m])) +# x, y = gens(GA) +# A = x^3 + y + y^2 +# B = y^3 + x + x^2 +# c = two_block_group_algebra_codes(A,B) +# @test code_n(c) == 72 && code_k(c) == 12 + +# # [[90, 8, 10]] +# l=15; m=3 +# GA = group_algebra(GF(2), abelian_group([l, m])) +# x, y = gens(GA) +# A = x^9 + y + y^2 +# B = 1 + x^2 + x^7 +# c = two_block_group_algebra_codes(A,B) +# @test code_n(c) == 90 && code_k(c) == 8 + +# # [[108, 8, 10]] +# l=9; m=6 +# GA = group_algebra(GF(2), abelian_group([l, m])) +# x, y = gens(GA) +# A = x^3 + y + y^2 +# B = y^3 + x + x^2 +# c = two_block_group_algebra_codes(A,B) +# @test code_n(c) == 108 && code_k(c) == 8 + +# # [[144, 12, 12]] +# l=12; m=6 +# GA = group_algebra(GF(2), abelian_group([l, m])) +# x, y = gens(GA) +# A = x^3 + y + y^2 +# B = y^3 + x + x^2 +# c = two_block_group_algebra_codes(A,B) +# @test code_n(c) == 144 && code_k(c) == 12 + +# # [[288, 12, 12]] +# l=12; m=12 +# GA = group_algebra(GF(2), abelian_group([l, m])) +# x, y = gens(GA) +# A = x^3 + y^2 + y^7 +# B = y^3 + x + x^2 +# c = two_block_group_algebra_codes(A,B) +# @test code_n(c) == 288 && code_k(c) == 12 + +# # [[360, 12, ≤ 24]] +# l=30; m=6 +# GA = group_algebra(GF(2), abelian_group([l, m])) +# x, y = gens(GA) +# A = x^9 + y + y^2 +# B = y^3 + x^25 + x^26 +# c = two_block_group_algebra_codes(A,B) +# @test code_n(c) == 360 && code_k(c) == 12 + +# # [[756, 16, ≤ 34]] +# l=21; m=18 +# GA = group_algebra(GF(2), abelian_group([l, m])) +# x, y = gens(GA) +# A = x^3 + y^10 + y^17 +# B = y^5 + x^3 + x^19 +# c = two_block_group_algebra_codes(A,B) +# @test code_n(c) == 756 && code_k(c) == 16 +# end + +# @testset "Reproduce Table 1 berthusen2024toward" begin +# # [[72, 8, 6]] +# l=12; m=3 +# GA = group_algebra(GF(2), abelian_group([l, m])) +# x, y = gens(GA) +# A = x^9 + y + y^2 +# B = 1 + x + x^11 +# c = two_block_group_algebra_codes(A,B) +# @test code_n(c) == 72 && code_k(c) == 8 + +# # [[90, 8, 6]] +# l=9; m=5 +# GA = group_algebra(GF(2), abelian_group([l, m])) +# x, y = gens(GA) +# A = x^8 + y^4 + y +# B = y^5 + x^8 + x^7 +# c = two_block_group_algebra_codes(A,B) +# @test code_n(c) == 90 && code_k(c) == 8 + +# # [[120, 8, 8]] +# l=12; m=5 +# GA = group_algebra(GF(2), abelian_group([l, m])) +# x, y = gens(GA) +# A = x^10 + y^4 + y +# B = 1 + x + x^2 +# c = two_block_group_algebra_codes(A,B) +# @test code_n(c) == 120 && code_k(c) == 8 + +# # [[150, 8, 8]] +# l=15; m=5 +# GA = group_algebra(GF(2), abelian_group([l, m])) +# x, y = gens(GA) +# A = x^5 + y^2 + y^3 +# B = y^2 + x^7 + x^6 +# c = two_block_group_algebra_codes(A,B) +# @test code_n(c) == 150 && code_k(c) == 8 + +# # [[196, 12, 8]] +# l=14; m=7 +# GA = group_algebra(GF(2), abelian_group([l, m])) +# x, y = gens(GA) +# A = x^6 + y^5 + y^6 +# B = 1 + x^4 + x^13 +# c = two_block_group_algebra_codes(A,B) +# @test code_n(c) == 196 && code_k(c) == 12 +# end + +# @testset "Reproduce Table 1 wang2024coprime" begin +# # [[54, 8, 6]] +# l=3; m=9 +# GA = group_algebra(GF(2), abelian_group([l, m])) +# x, y = gens(GA) +# A = 1 + y^2 + y^4 +# B = y^3 + x + x^2 +# c = two_block_group_algebra_codes(A,B) +# @test code_n(c) == 54 && code_k(c) == 8 + +# # [[98, 6, 12]] +# l=7; m=7 +# GA = group_algebra(GF(2), abelian_group([l, m])) +# x, y = gens(GA) +# A = x^3 + y^5 + y^6 +# B = y^2 + x^3 + x^5 +# c = two_block_group_algebra_codes(A,B) +# @test code_n(c) == 98 && code_k(c) == 6 + +# # [[126, 8, 10]] +# l=3; m=21 +# GA = group_algebra(GF(2), abelian_group([l, m])) +# x, y = gens(GA) +# A = 1 + y^2 + y^10 +# B = y^3 + x + x^2 +# c = two_block_group_algebra_codes(A,B) +# @test code_n(c) == 126 && code_k(c) == 8 + +# # [[150, 16, 8]] +# l=5; m=15 +# GA = group_algebra(GF(2), abelian_group([l, m])) +# x, y = gens(GA) +# A = 1 + y^6 + y^8 +# B = y^5 + x + x^4 +# c = two_block_group_algebra_codes(A,B) +# @test code_n(c) == 150 && code_k(c) == 16 + +# # [[162, 8, 14]] +# l=3; m=27 +# GA = group_algebra(GF(2), abelian_group([l, m])) +# x, y = gens(GA) +# A = 1 + y^10 + y^14 +# B = y^12 + x + x^2 +# c = two_block_group_algebra_codes(A,B) +# @test code_n(c) == 162 && code_k(c) == 8 + +# # [[180, 8, 16]] +# l=6; m=15 +# GA = group_algebra(GF(2), abelian_group([l, m])) +# x, y = gens(GA) +# A = x^3 + y + y^2 +# B = y^6 + x^4 + x^5 +# c = two_block_group_algebra_codes(A,B) +# @test code_n(c) == 180 && code_k(c) == 8 +# end +# end