Skip to content

Commit 7b444e9

Browse files
Fe-r-ozFe-r-ozKrastanov
authored
Binary Golay codes: [24, 12, 8] and [23, 12, 7] (#276)
Co-authored-by: Fe-r-oz <[email protected]> Co-authored-by: Stefan Krastanov <[email protected]>
1 parent 43febd9 commit 7b444e9

File tree

8 files changed

+249
-5
lines changed

8 files changed

+249
-5
lines changed

docs/src/references.bib

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -419,13 +419,13 @@ @article{RevModPhys.87.307
419419
}
420420

421421
@misc{goodenough2024bipartiteentanglementnoisystabilizer,
422-
title={Bipartite entanglement of noisy stabilizer states through the lens of stabilizer codes},
422+
title={Bipartite entanglement of noisy stabilizer states through the lens of stabilizer codes},
423423
author={Kenneth Goodenough and Aqil Sajjad and Eneet Kaur and Saikat Guha and Don Towsley},
424424
year={2024},
425425
eprint={2406.02427},
426426
archivePrefix={arXiv},
427427
primaryClass={quant-ph},
428-
url={https://arxiv.org/abs/2406.02427},
428+
url={https://arxiv.org/abs/2406.02427},
429429
}
430430

431431
@article{panteleev2021degenerate,
@@ -532,7 +532,7 @@ @article{wang2024coprime
532532
}
533533

534534
@misc{voss2024multivariatebicyclecodes,
535-
title={Multivariate Bicycle Codes},
535+
title={Multivariate Bicycle Codes},
536536
author={Lukas Voss and Sim Jian Xian and Tobias Haug and Kishor Bharti},
537537
year={2024},
538538
eprint={2406.19151},
@@ -561,3 +561,26 @@ @article{haah2011local
561561
pages={042330},
562562
year={2011},
563563
}
564+
565+
@article{golay1949notes,
566+
title={Notes on digital coding},
567+
author={Golay, Marcel JE},
568+
journal={Proc. IEEE},
569+
volume={37},
570+
pages={657},
571+
year={1949}
572+
}
573+
574+
@book{huffman2010fundamentals,
575+
title={Fundamentals of error-correcting codes},
576+
author={Huffman, W Cary and Pless, Vera},
577+
year={2010},
578+
publisher={Cambridge university press}
579+
}
580+
581+
@article{bhatia2018mceliece,
582+
title={McEliece cryptosystem based on extended Golay code},
583+
author={Bhatia, Amandeep Singh and Kumar, Ajay},
584+
journal={arXiv preprint arXiv:1811.06246},
585+
year={2018}
586+
}

docs/src/references.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ For classical code construction routines:
5656
- [bose1960class](@cite)
5757
- [bose1960further](@cite)
5858
- [error2024lin](@cite)
59+
- [golay1949notes](@cite)
60+
- [huffman2010fundamentals](@cite)
61+
- [bhatia2018mceliece](@cite)
5962

6063
# References
6164

src/ecc/ECC.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,10 +384,11 @@ include("codes/gottesman.jl")
384384
include("codes/surface.jl")
385385
include("codes/concat.jl")
386386
include("codes/random_circuit.jl")
387+
include("codes/quantumreedmuller.jl")
387388
include("codes/classical/reedmuller.jl")
388389
include("codes/classical/recursivereedmuller.jl")
389390
include("codes/classical/bch.jl")
390-
include("codes/quantumreedmuller.jl")
391+
include("codes/classical/golay.jl")
391392

392393
# qLDPC
393394
include("codes/classical/lifted.jl")

src/ecc/codes/classical/golay.jl

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
"""
2+
The family of classical binary Golay codes were discovered by Edouard Golay
3+
in his 1949 paper [golay1949notes](@cite), where he described the binary
4+
`[23, 12, 7]` Golay code.
5+
6+
There are two binary Golay codes:
7+
8+
- Binary `[23, 12, 7]` Golay code: The perfect code with code length `n = 23`
9+
and dimension `k = 12`. By puncturing in any of the coordinates of parity check
10+
matrix `H` = `[24, 12, 8]`, we obtain a `[23, 12, 7]` Golay code.
11+
12+
- Extended Binary `[24, 12, 8]` Golay code: Obtained by adding a parity check bit
13+
to `[23, 12, 7]`. The bordered reverse circulant matrix `(A)` of `[24, 12, 8]`
14+
Golay code is self-dual, i.e., `A₂₄` is same as A₂₄'.
15+
16+
The parity check matrix is defined as follows: `H₂₄ = [I₁₂ | A']` where `I₁₂` is the
17+
`12 × 12` identity matrix and `A` is a bordered reverse circulant matrix. Puncturing
18+
and then extending any column in​ with an overall parity check `H₂₃` reconstructs
19+
the original parity check matrix `H₂₄`. Thus, all punctured codes are equivalent.
20+
21+
The ECC Zoo has an [entry for this family](https://errorcorrectionzoo.org/c/golay).
22+
"""
23+
struct Golay <: ClassicalCode
24+
n::Int
25+
26+
function Golay(n)
27+
if !(n in (23, 24))
28+
throw(ArgumentError("Invalid parameters: `n` must be either 24 or 23 to obtain a valid code."))
29+
end
30+
new(n)
31+
end
32+
end
33+
34+
# bordered reverse circulant matrix (see section 1.9.1, pg. 30-33) of [huffman2010fundamentals](@cite).
35+
function _create_A₂₄_golay(n::Int)
36+
A = zeros(Int, n ÷ 2, n ÷ 2)
37+
# Define the squared values modulo 11.
38+
squares_mod₁₁ = [0, 1, 4, 9, 5, 3, 3, 5, 9, 4, 1]
39+
A[1, 2:end] .= 1
40+
A[2, 1] = 1
41+
for i in squares_mod₁₁
42+
A[2, i + 2] = 1
43+
end
44+
# Fill in the rest of the rows using the reverse circulant property.
45+
for i in 3:n ÷ 2
46+
A[i, 2:end] = circshift(A[i - 1, 2:end], -1)
47+
A[i, 1] = 1
48+
end
49+
return A
50+
end
51+
52+
function generator(g::Golay)
53+
if g.n == 24
54+
A₂₄ = _create_A₂₄_golay(24)
55+
I₁₂ = LinearAlgebra.Diagonal(ones(Int, g.n ÷ 2))
56+
G₂₄ = hcat(I₁₂, (A₂₄)')
57+
return G₂₄
58+
else
59+
A₂₄ = _create_A₂₄_golay(24)
60+
A₂₃ = A₂₄[:, 1:end - 1]
61+
I₁₂ = LinearAlgebra.Diagonal(ones(Int, g.n ÷ 2))
62+
G₂₃ = hcat(I₁₂, (A₂₃)')
63+
return G₂₃
64+
end
65+
end
66+
67+
function parity_checks(g::Golay)
68+
if g.n == 24
69+
A₂₄ = _create_A₂₄_golay(24)
70+
I₁₂ = LinearAlgebra.Diagonal(ones(Int, g.n ÷ 2))
71+
H₂₄ = hcat((A₂₄)', I₁₂)
72+
return H₂₄
73+
else
74+
A₂₄ = _create_A₂₄_golay(24)
75+
A₂₃ = A₂₄[:, 1:end - 1]
76+
I₁₂ = LinearAlgebra.Diagonal(ones(Int, g.n ÷ 2))
77+
H₂₃ = hcat((A₂₃)', I₁₂)
78+
return H₂₃
79+
end
80+
end
81+
82+
code_n(g::Golay) = g.n
83+
84+
code_k(g::Golay) = 12
85+
86+
distance(g::Golay) = code_n(g::Golay) - code_k(g::Golay) - 4

test/Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,6 @@ StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"
2727
Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3"
2828
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
2929
StridedViews = "4db3bf67-4bd7-4b4e-b153-31dc3fb37143"
30+
StyledStrings = "f489334b-da3d-4c2e-b8f0-e476e12c162b"
3031
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
3132
TestItemRunner = "f8b46487-2199-4994-9208-9a1283c18c0a"

test/test_ecc_golay.jl

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
@testitem "ECC Golay" begin
2+
3+
using LinearAlgebra
4+
using QuantumClifford.ECC
5+
using QuantumClifford.ECC: AbstractECC, Golay, generator
6+
using Nemo: matrix, GF, echelon_form
7+
8+
# Theorem: Let `C` be a binary linear code. If `C` is self-orthogonal and
9+
# has a generator matrix `G` where each row has weight divisible by four,
10+
# then every codeword of `C` has weight divisible by four. `H₂₄` is self-dual
11+
# because its generator matrix has all rows with weight divisible by four.
12+
# Thus, all codewords of `H₂₄` must have weights divisible by four. Refer to
13+
# pg. 30 to 33 of Ch1 of Fundamentals of Error Correcting Codes by Huffman,
14+
# Cary and Pless, Vera.
15+
function code_weight_property(matrix)
16+
for row in eachrow(matrix)
17+
count = sum(row)
18+
if count % 4 == 0
19+
return true
20+
end
21+
end
22+
return false
23+
end
24+
25+
# Test the equivalence of punctured and extended code by verifying that puncturing
26+
# the binary parity check matrix H₂₄ in any coordinate and then extending it by adding
27+
# an overall parity check in the same position yields the original matrix H₂₄.
28+
# Steps:
29+
# 1) Puncture the Code: Remove the i-th column from H₂₄ to create a punctured matrix
30+
# H₂₃. Note: H₂₃ = H[:, [1:i-1; i+1:end]]
31+
# 2) Extend the Code: Add a column in the same position to ensure each row has even
32+
# parity. Note: H'₂₄ = [H₂₃[:, 1:i-1] c H₂₃[:, i:end]]. Here, c is a column vector
33+
# added to ensure each row in H'₂₄ has even parity.
34+
# 3) Equivalence Check: Verify that H'₂₄ = H₂₄.
35+
function puncture_code(mat, i)
36+
return mat[:, [1:i-1; i+1:end]]
37+
end
38+
39+
function extend_code(mat, i)
40+
k, _ = size(mat)
41+
extended_mat = hcat(mat[:, 1:i-1], zeros(Bool, k, 1), mat[:, i:end])
42+
# Calculate the parity for each row
43+
for row in 1:k
44+
row_parity = sum(mat[row, :]) % 2 == 1
45+
extended_mat[row, i] = row_parity
46+
end
47+
return extended_mat
48+
end
49+
50+
function minimum_distance(H)
51+
n = size(H, 2)
52+
min_dist = n + 1
53+
for x_bits in 1:(2^n - 1)
54+
x = reverse(digits(x_bits, base=2, pad=n))
55+
xᵀ = reshape(x, :, 1)
56+
if all(mod.(H * xᵀ, 2) .== 0)
57+
weight = sum(x)
58+
min_dist = min(min_dist, weight)
59+
end
60+
end
61+
return min_dist
62+
end
63+
64+
@testset "Testing binary Golay codes properties" begin
65+
test_cases = [(24, 12), (23, 12)]
66+
for (n, k) in test_cases
67+
H = parity_checks(Golay(n))
68+
mat = matrix(GF(2), parity_checks(Golay(n)))
69+
computed_rank = rank(mat)
70+
@test computed_rank == n - k
71+
end
72+
73+
# [24, 12, 8] binary Golay code is a self-dual code [huffman2010fundamentals](@cite).
74+
H = parity_checks(Golay(24))
75+
@test code_weight_property(H) == true
76+
@test H[:, (12 + 1):end] == H[:, (12 + 1):end]'
77+
# Example taken from [huffman2010fundamentals](@cite).
78+
@test parity_checks(Golay(24)) == [0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0;
79+
1 1 1 0 1 1 1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0;
80+
1 1 0 1 1 1 0 0 0 1 0 1 0 0 1 0 0 0 0 0 0 0 0 0;
81+
1 0 1 1 1 0 0 0 1 0 1 1 0 0 0 1 0 0 0 0 0 0 0 0;
82+
1 1 1 1 0 0 0 1 0 1 1 0 0 0 0 0 1 0 0 0 0 0 0 0;
83+
1 1 1 0 0 0 1 0 1 1 0 1 0 0 0 0 0 1 0 0 0 0 0 0;
84+
1 1 0 0 0 1 0 1 1 0 1 1 0 0 0 0 0 0 1 0 0 0 0 0;
85+
1 0 0 0 1 0 1 1 0 1 1 1 0 0 0 0 0 0 0 1 0 0 0 0;
86+
1 0 0 1 0 1 1 0 1 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0;
87+
1 0 1 0 1 1 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0;
88+
1 1 0 1 1 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0;
89+
1 0 1 1 0 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1]
90+
91+
# minimum distance test
92+
# [24, 12, 8]
93+
H = parity_checks(Golay(24))
94+
@test minimum_distance(H) == 8
95+
# [23, 12, 7]
96+
H = parity_checks(Golay(23))
97+
@test minimum_distance(H) == 7
98+
99+
# cross-verifying the canonical equivalence of bordered reverse circulant matrix (A)
100+
# from [huffman2010fundamentals](@cite) with matrix A taken from [bhatia2018mceliece](@cite).
101+
A = [1 1 0 1 1 1 0 0 0 1 0 1;
102+
1 0 1 1 1 0 0 0 1 0 1 1;
103+
0 1 1 1 0 0 0 1 0 1 1 1;
104+
1 1 1 0 0 0 1 0 1 1 0 1;
105+
1 1 0 0 0 1 0 1 1 0 1 1;
106+
1 0 0 0 1 0 1 1 0 1 1 1;
107+
0 0 0 1 0 1 1 0 1 1 1 1;
108+
0 0 1 0 1 1 0 1 1 1 0 1;
109+
0 1 0 1 1 0 1 1 1 0 0 1;
110+
1 0 1 1 0 1 1 1 0 0 0 1;
111+
0 1 1 0 1 1 1 0 0 0 1 1;
112+
1 1 1 1 1 1 1 1 1 1 1 0]
113+
114+
H = parity_checks(Golay(24))
115+
@test echelon_form(matrix(GF(2), A)) == echelon_form(matrix(GF(2), H[1:12, 1:12]))
116+
# test self-duality for extended Golay code, G == H
117+
@test echelon_form(matrix(GF(2), generator(Golay(24)))) == echelon_form(matrix(GF(2), parity_checks(Golay(24))))
118+
119+
# All punctured and extended matrices are equivalent to the H₂₄. Test each column for puncturing and extending.
120+
for i in 1:24
121+
punctured_mat = puncture_code(H, i)
122+
extended_mat = extend_code(punctured_mat, i)
123+
@test extended_mat == H
124+
end
125+
end
126+
end

test/test_ecc_throws.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
@testitem "ECC throws" begin
22

3-
using QuantumClifford.ECC: ReedMuller, BCH, RecursiveReedMuller
3+
using QuantumClifford.ECC: ReedMuller, BCH, RecursiveReedMuller, Golay
44

55
@test_throws ArgumentError ReedMuller(-1, 3)
66
@test_throws ArgumentError ReedMuller(1, 0)
@@ -12,4 +12,6 @@
1212
@test_throws ArgumentError RecursiveReedMuller(-1, 3)
1313
@test_throws ArgumentError RecursiveReedMuller(1, 0)
1414
@test_throws ArgumentError RecursiveReedMuller(4, 2)
15+
16+
@test_throws ArgumentError Golay(21)
1517
end

test/test_jet.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using AbstractAlgebra
1111
using Hecke
1212
using StaticArrays
13+
using StyledStrings
1314

1415
rep = report_package("QuantumClifford";
1516
ignored_modules=(
@@ -23,6 +24,7 @@
2324
AnyFrameModule(AbstractAlgebra),
2425
AnyFrameModule(Hecke),
2526
AnyFrameModule(StaticArrays),
27+
AnyFrameModule(StyledStrings),
2628
))
2729

2830
@show rep

0 commit comments

Comments
 (0)