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

Implementing Bivariate Bicycle Codes using 2BGA as the parent via Hecke's Group Algebra #399

Merged
merged 9 commits into from
Nov 5, 2024
11 changes: 11 additions & 0 deletions docs/src/references.bib
Original file line number Diff line number Diff line change
Expand Up @@ -487,3 +487,14 @@ @article{anderson2014fault
year={2014},
publisher={APS}
}

@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}
}
5 changes: 3 additions & 2 deletions ext/QuantumCliffordHeckeExt/QuantumCliffordHeckeExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ using DocStringExtensions
import QuantumClifford, LinearAlgebra
import Hecke: Group, GroupElem, AdditiveGroup, AdditiveGroupElem,
GroupAlgebra, GroupAlgebraElem, FqFieldElem, representation_matrix, dim, base_ring,
multiplication_table, coefficients, abelian_group, group_algebra
multiplication_table, coefficients, abelian_group, group_algebra,
FinGenAbGroup, FinGenAbGroupElem, one
import Nemo
import Nemo: characteristic, matrix_repr, GF, ZZ, lift

import QuantumClifford.ECC: AbstractECC, CSS, ClassicalCode,
hgp, code_k, code_n, code_s, iscss, parity_checks, parity_checks_x, parity_checks_z, parity_checks_xz,
two_block_group_algebra_codes, generalized_bicycle_codes, bicycle_codes
two_block_group_algebra_codes, generalized_bicycle_codes, bicycle_codes, bivariate_bicycle_codes

include("types.jl")
include("lifted.jl")
Expand Down
44 changes: 41 additions & 3 deletions ext/QuantumCliffordHeckeExt/lifted_product.jl
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ code_s(c::LPCode) = size(c.repr(zero(c.GA)), 1) * (size(c.A, 1) * size(c.B, 1) +
Two-block group algebra (2GBA) codes, which are a special case of lifted product codes
from two group algebra elements `a` and `b`, used as `1x1` base matrices.

See also: [`LPCode`](@ref), [`generalized_bicycle_codes`](@ref), [`bicycle_codes`](@ref)
See also: [`LPCode`](@ref), [`generalized_bicycle_codes`](@ref), [`bicycle_codes`](@ref), [`bivariate_bicycle_codes`](@ref)
""" # TODO doctest example
function two_block_group_algebra_codes(a::GroupAlgebraElem, b::GroupAlgebraElem)
A = reshape([a], (1, 1))
Expand All @@ -166,7 +166,7 @@ Generalized bicycle codes, which are a special case of 2GBA codes (and therefore
Here the group is chosen as the cyclic group of order `l`,
and the base matrices `a` and `b` are the sum of the group algebra elements corresponding to the shifts `a_shifts` and `b_shifts`.

See also: [`two_block_group_algebra_codes`](@ref), [`bicycle_codes`](@ref).
See also: [`two_block_group_algebra_codes`](@ref), [`bicycle_codes`](@ref), [`bivariate_bicycle_codes`](@ref)

A [[254, 28, 14 ≤ d ≤ 20]] code from (A1) in Appendix B of [panteleev2021degenerate](@cite).

Expand All @@ -189,10 +189,48 @@ Bicycle codes are a special case of generalized bicycle codes,
where `a` and `b` are conjugate to each other.
The order of the cyclic group is `l`, and the shifts `a_shifts` and `b_shifts` are reverse to each other.

See also: [`two_block_group_algebra_codes`](@ref), [`generalized_bicycle_codes`](@ref).
See also: [`two_block_group_algebra_codes`](@ref), [`generalized_bicycle_codes`](@ref), [`bivariate_bicycle_codes`](@ref)
""" # TODO doctest example
function bicycle_codes(a_shifts::Array{Int}, l::Int)
GA = group_algebra(GF(2), abelian_group(l))
a = sum(GA[n÷l+1] for n in a_shifts)
two_block_group_algebra_codes(a, group_algebra_conj(a))
end

"""
Bivariate Bicycle codes are a class of Abelian 2BGA codes formed by the direct product
of two cyclic groups `ℤₗ × ℤₘ`. The parameters `l` and `m` represent the orders of the
first and second cyclic groups, respectively.

The ECC Zoo has an [entry for this family](https://errorcorrectionzoo.org/c/q-ary_bch).

See also: [`two_block_group_algebra_codes`](@ref), [`generalized_bicycle_codes`](@ref),
[`bicycle_codes`](@ref), [`LPCode`](@ref)

A [[756, 16, ≤ 34]] code from Table 3 of [bravyi2024high](@cite).

```jldoctest
julia> import Hecke: group_algebra, GF, abelian_group, gens; # hide

julia> l=21; m=18;

julia> GA = group_algebra(GF(2), abelian_group([l, m]));

julia> x, y = gens(GA);

julia> A = [x^3 , y^10 , y^17];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why write this down as [x^3 , y^10 , y^17] instead of x^3 + y^10 + y^17 and use directly two_block_group_algebra_codes? What is the advantage of the list notation?

Copy link
Contributor Author

@Fe-r-oz Fe-r-oz Nov 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. For regular abelian groups via Hecke's group algebra, we can use the non-list notation.

The advantage of list notation is when using finitely presented groups from Oscar with specific group presentations which is not related to this PR.

julia> b_elts = 1 +  s + r^6 +  s^3 * r + s * r^7 +  s^3 * r^5;
ERROR: MethodError: no method matching +(::Int64, ::FPGroupElem)
The function `+` exists, but no method is defined for this combination of argument types.

Closest candidates are:
  +(::Any, ::Any, ::Any, ::Any...)
   @ Base operators.jl:596
  +(::Oscar.StraightLinePrograms.Lazy, ::Any)
   @ Oscar ~/.julia/packages/Oscar/2lR8w/src/StraightLinePrograms/lazy.jl:98
  +(::Any, ::Oscar.StraightLinePrograms.Lazy)
   @ Oscar ~/.julia/packages/Oscar/2lR8w/src/StraightLinePrograms/lazy.jl:99
  ...

Stacktrace:
 [1] +(::Int64, ::FPGroupElem, ::FPGroupElem, ::FPGroupElem, ::FPGroupElem, ::FPGroupElem)
   @ Base ./operators.jl:596
 [2] top-level scope
   @ REPL[9]:1


julia> B = [y^5 , x^3 , x^19];

julia> c = bivariate_bicycle_codes(A,B,GA);

julia> code_n(c), code_k(c)
(756, 16)
```
"""
function bivariate_bicycle_codes(A::Vector{GroupAlgebraElem{FqFieldElem, GroupAlgebra{FqFieldElem, FinGenAbGroup, FinGenAbGroupElem}}}, B::Vector{GroupAlgebraElem{FqFieldElem, GroupAlgebra{FqFieldElem, FinGenAbGroup, FinGenAbGroupElem}}}, GA::GroupAlgebra{FqFieldElem, FinGenAbGroup, FinGenAbGroupElem})
Fe-r-oz marked this conversation as resolved.
Show resolved Hide resolved
a = sum(GA(x) for x in A)
b = sum(GA(x) for x in B)
c = two_block_group_algebra_codes(a,b)
return c
end
1 change: 1 addition & 0 deletions src/ecc/ECC.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export parity_checks, parity_checks_x, parity_checks_z, iscss,
Shor9, Steane7, Cleve8, Perfect5, Bitflip3,
Toric, Gottesman, Surface, Concat, CircuitCode, QuantumReedMuller,
LPCode, two_block_group_algebra_codes, generalized_bicycle_codes, bicycle_codes,
bivariate_bicycle_codes,
random_brickwork_circuit_code, random_all_to_all_circuit_code,
evaluate_decoder,
CommutationCheckECCSetup, NaiveSyndromeECCSetup, ShorSyndromeECCSetup,
Expand Down
3 changes: 3 additions & 0 deletions src/ecc/codes/lifted_product.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ function generalized_bicycle_codes end

"""Implemented in a package extension with Hecke."""
function bicycle_codes end

"""Implemented in a package extension with Hecke."""
function bivariate_bicycle_codes end
30 changes: 28 additions & 2 deletions test/test_ecc_base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ using InteractiveUtils

import Nemo: GF
import LinearAlgebra
import Hecke: group_algebra, abelian_group, gens
import Hecke: group_algebra, abelian_group, gens, one

# generate instances of all implemented codes to make sure nothing skips being checked

Expand Down Expand Up @@ -56,14 +56,40 @@ A[LinearAlgebra.diagind(A, 5)] .= GA(1)
B = reshape([1 + x + x^6], (1, 1))
push!(other_lifted_product_codes, LPCode(A, B))

# A [[72, 12, 6]] code from Table 3 of [bravyi2024high](@cite).
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]
bb1 = bivariate_bicycle_codes(A,B,GA)

# A [[90, 8, 10]] code from Table 3 of [bravyi2024high](@cite).
l=15; m=3
GA = group_algebra(GF(2), abelian_group([l, m]))
x, y = gens(GA)
A = [x^9 , y , y^2]
B = [one(x), x^2 , x^7]
bb2 = bivariate_bicycle_codes(A,B,GA)

# A [[360, 12, ≤ 24]] code from Table 3 of [bravyi2024high](@cite).
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]
bb3 = bivariate_bicycle_codes(A,B,GA)

test_bb_codes = [bb1, bb2, bb3]

const code_instance_args = Dict(
:Toric => [(3,3), (4,4), (3,6), (4,3), (5,5)],
:Surface => [(3,3), (4,4), (3,6), (4,3), (5,5)],
:Gottesman => [3, 4, 5],
:CSS => (c -> (parity_checks_x(c), parity_checks_z(c))).([Shor9(), Steane7(), Toric(4, 4)]),
: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, other_lifted_product_codes)),
:LPCode => (c -> (c.A, c.B)).(vcat(LP04, LP118, test_gb_codes, test_bb_codes, other_lifted_product_codes)),
:QuantumReedMuller => [3, 4, 5]
)

Expand Down
173 changes: 173 additions & 0 deletions test/test_ecc_bivaraite_bicycle_as_twobga.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
@testitem "ECC Bivaraite Bicycle as 2BGA" begin
using Hecke
using Hecke: group_algebra, GF, abelian_group, gens, one
using QuantumClifford.ECC: bivariate_bicycle_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 = bivariate_bicycle_codes(A,B,GA)
@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 = [one(x), x^2 , x^7]
c = bivariate_bicycle_codes(A,B,GA)
@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 = bivariate_bicycle_codes(A,B,GA)
@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 = bivariate_bicycle_codes(A,B,GA)
@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 = bivariate_bicycle_codes(A,B,GA)
@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 = bivariate_bicycle_codes(A,B,GA)
@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 = bivariate_bicycle_codes(A,B,GA)
@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 = [one(x), x , x^11]
c = bivariate_bicycle_codes(A,B,GA)
@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 = bivariate_bicycle_codes(A,B,GA)
@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 = [one(x), x , x^2]
c = bivariate_bicycle_codes(A,B,GA)
@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 = bivariate_bicycle_codes(A,B,GA)
@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 = [one(x), x^4 , x^13]
c = bivariate_bicycle_codes(A,B,GA)
@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 = [one(x), y^2, y^4]
B = [y^3 , x , x^2]
c = bivariate_bicycle_codes(A,B,GA)
@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 = bivariate_bicycle_codes(A,B,GA)
@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 = [one(x), y^2, y^10]
B = [y^3 , x , x^2]
c = bivariate_bicycle_codes(A,B,GA)
@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 = [one(x), y^6, y^8]
B = [y^5 , x , x^4]
c = bivariate_bicycle_codes(A,B,GA)
@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 = [one(x), y^10, y^14]
B = [y^12 , x , x^2]
c = bivariate_bicycle_codes(A,B,GA)
@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 = bivariate_bicycle_codes(A,B,GA)
@test code_n(c) == 180 && code_k(c) == 8
end
end
Loading