From 70f6b46d153178d61578fb8d20d968769a0fbc24 Mon Sep 17 00:00:00 2001 From: Fe-r-oz Date: Sat, 14 Feb 2026 00:21:29 -0500 Subject: [PATCH 01/10] shortening and puncturing of classical linear binary codes --- docs/src/references.bib | 10 ++++++ src/QuantumExpanders.jl | 5 ++- src/utils.jl | 77 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 src/utils.jl diff --git a/docs/src/references.bib b/docs/src/references.bib index c93eeae..8bada7a 100644 --- a/docs/src/references.bib +++ b/docs/src/references.bib @@ -560,3 +560,13 @@ @misc{panteleev2022asymptoticallygoodquantumlocally primaryClass={cs.IT}, url={https://arxiv.org/abs/2111.03654}, } + +@misc{liu2020shortenedlinearcodesfinite, + title={Shortened Linear Codes over Finite Fields}, + author={Yang Liu and Cunsheng Ding and Chunming Tang}, + year={2020}, + eprint={2007.05901}, + archivePrefix={arXiv}, + primaryClass={cs.IT}, + url={https://arxiv.org/abs/2007.05901}, +} diff --git a/src/QuantumExpanders.jl b/src/QuantumExpanders.jl index 70e4313..06a84c2 100644 --- a/src/QuantumExpanders.jl +++ b/src/QuantumExpanders.jl @@ -25,6 +25,7 @@ using Multigraphs using ProgressMeter using DocStringExtensions +include("utils") include("cayley_graphs.jl") include("tensor_codes.jl") include("morgenstern.jl") @@ -51,6 +52,8 @@ export parity_matrix, parity_matrix_x, parity_matrix_z, parity_matrix_xz, code_n, code_k, # tensor codes uniformly_random_code_checkmatrix, dual_code, good_css, - normal_cayley_subset, GeneralizedQuantumTannerCode, find_random_generating_sets + normal_cayley_subset, GeneralizedQuantumTannerCode, find_random_generating_sets, + # shortening, puncturing + shorten, puncture end #module diff --git a/src/utils.jl b/src/utils.jl new file mode 100644 index 0000000..ce1251a --- /dev/null +++ b/src/utils.jl @@ -0,0 +1,77 @@ +""" +Puncturing and shortening are standard techniques for constructing new linear codes +from existing ones. + +Let C be an [n,k,d] linear code over GF(q) with parity-check matrix H, and let t ⊆ {1,…,n} +be a set of coordinate positions specified by `cols`. + +The shortened code C_t is obtained by restricting C to codewords that are zero on t and +then puncturing those coordinates, resulting in a code of length n − |t|. + +# Example + +```jldoctest +julia> using QuantumExpanders; using Nemo + +julia> H = [1 0 0 0 1 1; + 0 1 0 1 0 1; + 0 0 1 1 1 0]; + +julia> H_new = shorten(H, [6]) +3×5 Matrix{Int64}: + 1 1 1 0 0 + 0 1 0 1 0 + 1 0 0 0 1 + +julia> rank(matrix(GF(2), H_new)) +3 +``` +""" +function shorten(H::AbstractMatrix, cols::AbstractVector{<:Integer}) + G = Matrix{Int}(lift.(dual_code(matrix(ZZ, H)))) + keep_rows = [all(G[r,c] == 0 for c in cols) for r in 1:size(G,1)] + G_new = G[keep_rows, :] + keep_cols = setdiff(1:size(G_short,2), cols) + G_new = G_new[:, keep_cols] + H = Matrix{Int}(lift.(dual_code(matrix(ZZ, G_new)))) + return H +end + +""" +Let C be an [n, k, d] linear code over GF(q) with parity-check matrix H_B, and let t be a +set of coordinates given by `cols`. The punctured code Cₜ is obtained by deleting the +coordinates in t from every codeword of C. The resulting code is linear and has length +n − |t|. + +Returns a parity-check matrix for the punctured code Cₜ. The construction proceeds by +computing a generator matrix G of C from H_B, deleting the columns indexed by t, and then +computing a parity-check matrix for the resulting punctured code. + +Here is an example of puncturing the classical [6,3,3] code: + +```jldoctest +julia> using QuantumExpanders; using Nemo + +julia> H = [1 0 0 0 1 1; + 0 1 0 1 0 1; + 0 0 1 1 1 0]; + +julia> H_new = puncture(H, [6]) +2×5 Matrix{Int64}: + 1 1 1 0 0 + 1 1 0 1 1 + +julia> rank(matrix(GF(2), H_new)) +2 +``` + +Now, it is a [5,2,2] code. This distance is verified from [dist-m4ri](https://github.com/QEC-pages/dist-m4ri) program. + +""" +function puncture(H::AbstractMatrix, cols::AbstractVector{<:Integer}) + G = Matrix{Int}(lift.(dual_code(matrix(ZZ, H)))) + keep = setdiff(1:size(G,2), cols) + G_p = G[:, keep] + H = Matrix{Int}(lift.(dual_code(matrix(ZZ, G_p)))) + return H +end From e79ecc1c9c356a41222ae50db3a5431d79d00441 Mon Sep 17 00:00:00 2001 From: Fe-r-oz Date: Thu, 19 Feb 2026 10:39:28 -0500 Subject: [PATCH 02/10] add references --- docs/src/references.bib | 13 +++++++++++++ src/utils.jl | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/docs/src/references.bib b/docs/src/references.bib index 8bada7a..2fc8b9b 100644 --- a/docs/src/references.bib +++ b/docs/src/references.bib @@ -570,3 +570,16 @@ @misc{liu2020shortenedlinearcodesfinite primaryClass={cs.IT}, url={https://arxiv.org/abs/2007.05901}, } + +@article{Gundersen_2025, + title={Puncturing Quantum Stabilizer Codes}, + volume={6}, + ISSN={2641-8770}, + url={http://dx.doi.org/10.1109/JSAIT.2025.3562287}, + DOI={10.1109/jsait.2025.3562287}, + journal={IEEE Journal on Selected Areas in Information Theory}, + publisher={Institute of Electrical and Electronics Engineers (IEEE)}, + author={Gundersen, Jaron Skovsted and Christensen, René Bødker and Grassl, Markus and Popovski, Petar and Wisniewski, Rafał}, + year={2025}, + pages={74–84} } + diff --git a/src/utils.jl b/src/utils.jl index ce1251a..f7eb6bd 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -3,7 +3,7 @@ Puncturing and shortening are standard techniques for constructing new linear co from existing ones. Let C be an [n,k,d] linear code over GF(q) with parity-check matrix H, and let t ⊆ {1,…,n} -be a set of coordinate positions specified by `cols`. +be a set of coordinate positions specified by `cols`. See [Gundersen_2025](@cite). The shortened code C_t is obtained by restricting C to codewords that are zero on t and then puncturing those coordinates, resulting in a code of length n − |t|. From 0a14595f4eeea74e211ba598597ef355b33d788f Mon Sep 17 00:00:00 2001 From: Fe-r-oz Date: Thu, 19 Feb 2026 13:03:09 -0500 Subject: [PATCH 03/10] polish --- src/QuantumExpanders.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/QuantumExpanders.jl b/src/QuantumExpanders.jl index 06a84c2..c6e3e92 100644 --- a/src/QuantumExpanders.jl +++ b/src/QuantumExpanders.jl @@ -25,7 +25,7 @@ using Multigraphs using ProgressMeter using DocStringExtensions -include("utils") +include("utils.jl") include("cayley_graphs.jl") include("tensor_codes.jl") include("morgenstern.jl") From 474824e0bb63e8326ae4e38c902b73c190f8e711 Mon Sep 17 00:00:00 2001 From: Fe-r-oz Date: Thu, 19 Feb 2026 20:56:52 -0500 Subject: [PATCH 04/10] add tests --- src/utils.jl | 39 ------------------------------- test/test_quantum_tanner_codes.jl | 31 ++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 39 deletions(-) diff --git a/src/utils.jl b/src/utils.jl index f7eb6bd..28385de 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -1,42 +1,3 @@ -""" -Puncturing and shortening are standard techniques for constructing new linear codes -from existing ones. - -Let C be an [n,k,d] linear code over GF(q) with parity-check matrix H, and let t ⊆ {1,…,n} -be a set of coordinate positions specified by `cols`. See [Gundersen_2025](@cite). - -The shortened code C_t is obtained by restricting C to codewords that are zero on t and -then puncturing those coordinates, resulting in a code of length n − |t|. - -# Example - -```jldoctest -julia> using QuantumExpanders; using Nemo - -julia> H = [1 0 0 0 1 1; - 0 1 0 1 0 1; - 0 0 1 1 1 0]; - -julia> H_new = shorten(H, [6]) -3×5 Matrix{Int64}: - 1 1 1 0 0 - 0 1 0 1 0 - 1 0 0 0 1 - -julia> rank(matrix(GF(2), H_new)) -3 -``` -""" -function shorten(H::AbstractMatrix, cols::AbstractVector{<:Integer}) - G = Matrix{Int}(lift.(dual_code(matrix(ZZ, H)))) - keep_rows = [all(G[r,c] == 0 for c in cols) for r in 1:size(G,1)] - G_new = G[keep_rows, :] - keep_cols = setdiff(1:size(G_short,2), cols) - G_new = G_new[:, keep_cols] - H = Matrix{Int}(lift.(dual_code(matrix(ZZ, G_new)))) - return H -end - """ Let C be an [n, k, d] linear code over GF(q) with parity-check matrix H_B, and let t be a set of coordinates given by `cols`. The punctured code Cₜ is obtained by deleting the diff --git a/test/test_quantum_tanner_codes.jl b/test/test_quantum_tanner_codes.jl index 3f77b47..168817f 100644 --- a/test/test_quantum_tanner_codes.jl +++ b/test/test_quantum_tanner_codes.jl @@ -715,4 +715,35 @@ end end end + + @testset "Test Puncture" begin + for seed in 1:50 + G = small_group(12,1) + rng = MersenneTwister(seed) + A, B = find_random_generating_sets(G, 6, 5; rng=rng) + H_A = [1 0 0 0 1 1; + 0 1 0 1 0 1; + 0 0 1 1 1 0]; + G_A = Matrix{Int}(lift.(dual_code(matrix(ZZ, H_A)))) + H_B = puncture(H, [6]) + G_B = Matrix{Int}(lift.(dual_code(matrix(ZZ, H_B)))) + classical_code_pair = ((Matrix{Int}(H_A), G_A), (H_B, G_B)) + c = QuantumTannerCode(G, A, B, classical_code_pair) + @test stab_looks_good(parity_checks(c), remove_redundant_rows=true) + end + + # Here is an example of novel [[180, 2, 8]] code + G = small_group(12,1) + rng = MersenneTwister(1) + A, B = find_random_generating_sets(G, 6, 5; rng=rng) + H_A = [1 0 0 0 1 1; + 0 1 0 1 0 1; + 0 0 1 1 1 0]; + G_A = Matrix{Int}(lift.(dual_code(matrix(ZZ, H_A)))) + H_B = puncture(H, [6]) + G_B = Matrix{Int}(lift.(dual_code(matrix(ZZ, H_B)))) + classical_code_pair = ((Matrix{Int}(H_A), G_A), (H_B, G_B)) + c = QuantumTannerCode(G, A, B, classical_code_pair) + @test stab_looks_good(parity_checks(c), remove_redundant_rows=true) + end end From 0f3d410b623b10ba04e3345f99f7e767603abadd Mon Sep 17 00:00:00 2001 From: Fe-r-oz Date: Thu, 19 Feb 2026 20:58:12 -0500 Subject: [PATCH 05/10] polish --- src/QuantumExpanders.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/QuantumExpanders.jl b/src/QuantumExpanders.jl index c6e3e92..4586dc7 100644 --- a/src/QuantumExpanders.jl +++ b/src/QuantumExpanders.jl @@ -53,7 +53,7 @@ export # tensor codes uniformly_random_code_checkmatrix, dual_code, good_css, normal_cayley_subset, GeneralizedQuantumTannerCode, find_random_generating_sets, - # shortening, puncturing - shorten, puncture + # puncturing + puncture end #module From 8d0ca4124d52853b9f6ef70288686500965651b2 Mon Sep 17 00:00:00 2001 From: Fe-r-oz Date: Thu, 19 Feb 2026 22:18:52 -0500 Subject: [PATCH 06/10] polish --- test/test_quantum_tanner_codes.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_quantum_tanner_codes.jl b/test/test_quantum_tanner_codes.jl index 168817f..0515872 100644 --- a/test/test_quantum_tanner_codes.jl +++ b/test/test_quantum_tanner_codes.jl @@ -740,7 +740,7 @@ 0 1 0 1 0 1; 0 0 1 1 1 0]; G_A = Matrix{Int}(lift.(dual_code(matrix(ZZ, H_A)))) - H_B = puncture(H, [6]) + H_B = puncture(H_A, [6]) G_B = Matrix{Int}(lift.(dual_code(matrix(ZZ, H_B)))) classical_code_pair = ((Matrix{Int}(H_A), G_A), (H_B, G_B)) c = QuantumTannerCode(G, A, B, classical_code_pair) From 041dc0cabe654f782fbaadeb3881e30fbd35fcf0 Mon Sep 17 00:00:00 2001 From: Fe-r-oz Date: Fri, 20 Feb 2026 06:53:38 -0500 Subject: [PATCH 07/10] polish --- test/test_quantum_tanner_codes.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_quantum_tanner_codes.jl b/test/test_quantum_tanner_codes.jl index 0515872..903dbf2 100644 --- a/test/test_quantum_tanner_codes.jl +++ b/test/test_quantum_tanner_codes.jl @@ -725,7 +725,7 @@ 0 1 0 1 0 1; 0 0 1 1 1 0]; G_A = Matrix{Int}(lift.(dual_code(matrix(ZZ, H_A)))) - H_B = puncture(H, [6]) + H_B = puncture(H_A, [6]) G_B = Matrix{Int}(lift.(dual_code(matrix(ZZ, H_B)))) classical_code_pair = ((Matrix{Int}(H_A), G_A), (H_B, G_B)) c = QuantumTannerCode(G, A, B, classical_code_pair) From d7bb69674e585fe651e43bc7a5b0cface7a91857 Mon Sep 17 00:00:00 2001 From: Feroz Ahmed Mian Date: Fri, 20 Feb 2026 07:54:18 -0500 Subject: [PATCH 08/10] improve documentation --- src/utils.jl | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/utils.jl b/src/utils.jl index 28385de..36ad676 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -1,11 +1,13 @@ """ -Let C be an [n, k, d] linear code over GF(q) with parity-check matrix H_B, and let t be a -set of coordinates given by `cols`. The punctured code Cₜ is obtained by deleting the -coordinates in t from every codeword of C. The resulting code is linear and has length +Puncturing is a standard techniques for constructing new linear codes from existing ones ([liu2020shortenedlinearcodesfinit](@cite), [Gundersen_2025](@cite)). + +Let C be an [n, k, d] linear code over Galois field with characteristic 2 with parity-check matrix +``H_B``, and let t be a set of coordinates given by `cols`. The punctured code ``C_t`` is obtained +by deleting the coordinates in t from every codeword of C. The resulting code is linear and has length n − |t|. -Returns a parity-check matrix for the punctured code Cₜ. The construction proceeds by -computing a generator matrix G of C from H_B, deleting the columns indexed by t, and then +Returns a parity-check matrix for the punctured code ``C_t``. The construction proceeds by +computing a generator matrix G of C from ``H_B``, deleting the columns indexed by t, and then computing a parity-check matrix for the resulting punctured code. Here is an example of puncturing the classical [6,3,3] code: From 6ee3c0f17e70100bfe739a45affcc31198bb7aa5 Mon Sep 17 00:00:00 2001 From: Feroz Ahmed Mian Date: Fri, 20 Feb 2026 07:55:21 -0500 Subject: [PATCH 09/10] polish --- src/utils.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils.jl b/src/utils.jl index 36ad676..9e0a9e4 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -1,5 +1,5 @@ """ -Puncturing is a standard techniques for constructing new linear codes from existing ones ([liu2020shortenedlinearcodesfinit](@cite), [Gundersen_2025](@cite)). +Puncturing is a standard technique for constructing new linear codes from existing ones ([liu2020shortenedlinearcodesfinit](@cite), [Gundersen_2025](@cite)). Let C be an [n, k, d] linear code over Galois field with characteristic 2 with parity-check matrix ``H_B``, and let t be a set of coordinates given by `cols`. The punctured code ``C_t`` is obtained From 09f9c0092305be10063b10901c9284b0bcf8135f Mon Sep 17 00:00:00 2001 From: Feroz Ahmed Mian Date: Fri, 20 Feb 2026 08:00:25 -0500 Subject: [PATCH 10/10] polish --- src/utils.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils.jl b/src/utils.jl index 9e0a9e4..5b72d97 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -1,5 +1,5 @@ """ -Puncturing is a standard technique for constructing new linear codes from existing ones ([liu2020shortenedlinearcodesfinit](@cite), [Gundersen_2025](@cite)). +Puncturing is a standard technique for constructing new linear codes from existing ones ([liu2020shortenedlinearcodesfinite](@cite), [Gundersen_2025](@cite)). Let C be an [n, k, d] linear code over Galois field with characteristic 2 with parity-check matrix ``H_B``, and let t be a set of coordinates given by `cols`. The punctured code ``C_t`` is obtained