diff --git a/docs/src/references.bib b/docs/src/references.bib index c492d0ea7..e8309718e 100644 --- a/docs/src/references.bib +++ b/docs/src/references.bib @@ -386,3 +386,58 @@ @article{knill1996concatenated journal={arXiv preprint quant-ph/9608012}, year={1996} } + +@article{dur1987automorphism, + title={The automorphism groups of Reed-Solomon codes}, + author={D{\"u}r, Arne}, + journal={Journal of Combinatorial Theory, Series A}, + volume={44}, + number={1}, + pages={69--82}, + year={1987}, + publisher={Elsevier} +} + +@book{tomlinson2017error, + title={Error-correction coding and decoding: bounds, codes, decoders, analysis and applications}, + author={Tomlinson, Martin and Tjhai, Cen Jung and Ambroze, Marcel A and Ahmed, Mohammed and Jibril, Mubarak}, + year={2017}, + publisher={Springer Nature} +} + +@book{macwilliams1977theory, + title={The theory of error-correcting codes}, + author={MacWilliams, Florence Jessie and Sloane, Neil James Alexander}, + volume={16}, + year={1977}, + publisher={Elsevier} +} + +@book{peterson1972error, + title={Error-correcting codes}, + author={Peterson, William Wesley and Weldon, Edward J}, + year={1972}, + publisher={MIT press} +} + +@article{dorsch1974decoding, + title={A decoding algorithm for binary block codes and J-ary output channels (corresp.)}, + author={Dorsch, B}, + journal={IEEE Transactions on Information Theory}, + volume={20}, + number={3}, + pages={391--394}, + year={1974}, + publisher={IEEE} +} + +@article{seroussi1986mds, + title={On MDS extensions of generalized Reed-Solomon codes}, + author={Seroussi, Gadiel and Roth, Ron M}, + journal={IEEE Transactions on Information Theory}, + volume={32}, + number={3}, + pages={349--354}, + year={1986}, + publisher={IEEE} +} diff --git a/docs/src/references.md b/docs/src/references.md index b37e94d4e..14af7d219 100644 --- a/docs/src/references.md +++ b/docs/src/references.md @@ -48,6 +48,12 @@ For classical code construction routines: - [bose1960class](@cite) - [bose1960further](@cite) - [error2024lin](@cite) +- [dur1987automorphism](@cite) +- [tomlinson2017error](@cite) +- [macwilliams1977theory](@cite) +- [peterson1972error](@cite) +- [dorsch1974decoding](@cite) +- [seroussi1986mds](@cite) # References diff --git a/src/ecc/ECC.jl b/src/ecc/ECC.jl index bae3df389..f8cb85ec2 100644 --- a/src/ecc/ECC.jl +++ b/src/ecc/ECC.jl @@ -361,4 +361,5 @@ include("codes/surface.jl") include("codes/concat.jl") include("codes/classical/reedmuller.jl") include("codes/classical/bch.jl") +include("codes/classical/shortenedmds.jl") end #module diff --git a/src/ecc/codes/classical/shortenedmds.jl b/src/ecc/codes/classical/shortenedmds.jl new file mode 100644 index 000000000..238893db8 --- /dev/null +++ b/src/ecc/codes/classical/shortenedmds.jl @@ -0,0 +1,93 @@ +"""The family of `[2ᵐ + 1 - 3, k, 2ᵐ ⁺ ¹ - 3 - k]` Shortened Maximum Distance Separable `(ShortenedMDS)` codes are constructed from the `[2ᵐ + 1, k, 2ᵐ ⁺ ¹ - k]` Extended, Augmented Reed-Solomon codes from the corresponding first `x - 1` columns of latter's parity-check matrix, using `j = 0`, and setting `α₀, α₁, α₂, ..., αₓ ₋ ₁` to `α⁰, α¹, α², ..., αˣ ⁻ ¹` in the parity-check matrix. + +Denoting the `x` field elements as `0, α⁰, α¹, α²,... αˣ ⁻ ¹`, the shortened field parity-check matrix (`HF`) is given as follows: + +``` +(α⁰)ʲ (α¹)ʲ (α²)ʲ ... (αˣ ⁻ ¹)ʲ +(α⁰)ʲ ⁺ ¹ (α¹)ʲ ⁺ ¹ (α²)ʲ ⁺ ¹ ... (αˣ ⁻ ¹)ʲ ⁺ ¹ +(α⁰)ʲ ⁺ ² (α¹)ʲ ⁺ ² (α²)ʲ ⁺ ² ... (αˣ ⁻ ¹)ʲ ⁺ ² +(α⁰)ʲ ⁺ ˣ ⁻ ᵏ ⁻ ¹ (α¹)ʲ ⁺ ˣ ⁻ ᵏ ⁻ ¹ (α²)ʲ ⁺ ˣ ⁻ ᵏ ⁻ ¹ ... (αˣ ⁻ ¹)ʲ ⁺ ˣ ⁻ ᵏ ⁻ ¹ + . . . ... . + . . . ... . + . . . ... . +(α⁰)ʲ ⁺ ˣ ⁻ ᵏ (α¹)ʲ ⁺ ˣ ⁻ ᵏ (α²)ʲ ⁺ ˣ ⁻ ᵏ . ... (αˣ ⁻ ¹)ʲ ⁺ ˣ ⁻ ᵏ +``` + +For significant coding gain, code length is typically restricted to less than 200 bits. Modified Dorsch decoder [dorsch1974decoding](@cite) is recommended for near maximum likelihood decoding. + +Shortened MDS (`HF`) Matrix element expansion: + 1. Row expansion: Each row of in the field parity-check matrix is replaced with an `m`-by-`m` field matrix defined over the base field `GF(2ᵐ)`. + 2. Column expansion: Consequently, the elements in each column of expanded field parity-check matrix are converted to binary representations by substituting powers of a primitive element (`α`) in the Galois Field `GF(2ᵐ)` with their corresponding `m`-tuples over the Boolean Field `GF(2)`. + +You might be interested in consulting [tomlinson2017error](@cite), [macwilliams1977theory](@cite), [peterson1972error](@cite), [seroussi1986mds](@cite), [dur1987automorphism](@cite) and [Extending MDS Codes](https://www.unb.ca/faculty-staff/directory/_resources/pdf/sase/alderson/mds-codes.pdf) as well. +""" +abstract type AbstractPolynomialCode <: ClassicalCode end + +struct ShortenedMDS <: AbstractPolynomialCode + m::Int + t::Int + + function ShortenedMDS(m, t) + if m < 3 || t < 0 || t >= 2 ^ (m - 1) + throw(ArgumentError("Invalid parameters: m and t must be non-negative. Also, m > 3 and t < 2 ^ (m - 1) in order to obtain a valid code.")) + end + new(m, t) + end +end + +""" +`parity_checks(ShortenedMDS(m, t))` +- `m`: The positive integer defining the degree of the finite (Galois) field, `GF(2ᵐ)`. +- `t`: The positive integer specifying the number of correctable errors. +""" +function parity_checks(rs::ShortenedMDS) + GF2ʳ, a = finite_field(2, rs.m, "a") + s_symbols = 3 # 3-level quantization. + x = 2 ^ rs.m + 1 - s_symbols + k = 2 ^ rs.m - 1 - 2 * rs.t + HField = Matrix{FqFieldElem}(undef, x - k + 1, x) + for j in 1:x + HField[1, j] = a ^ 0 + end + for i in 1: x - k + 1 + HField[i, 1] = a ^ 0 + end + for i in 2:x - k + 1 + for j in 2:x + HField[i, j] = (a ^ (j - 1)) ^ (i - 2) + end + end + HSeed = vcat(HField[1:1, :], HField[3:end, :]) + HTemp2 = Matrix{FqFieldElem}(undef, rs.m, x) + HFieldExpanded = Matrix{FqFieldElem}(undef, rs.m * k, x) + g = 1 + while g <= rs.m * k + for i in 1:x - k + for p in 1:rs.m + HTemp2[p:p, :] = reshape(HSeed[i, :].*a ^ (p - 1) , 1, :) + end + if g > rs.m * k + break + end + HFieldExpanded[g:g + rs.m - 1, :] .= HTemp2 + g = g + rs.m + end + end + H = Matrix{Bool}(undef, rs.m * k, rs.m * x) + for i in 1:rs.m * k + for j in 1:x + col_start = (j - 1) * rs.m + 1 + col_end = col_start + rs.m - 1 + t_tuple = Bool[] + for k in 0:rs.m - 1 + push!(t_tuple, !is_zero(coeff(HFieldExpanded[i, j], k))) + end + H[i, col_start:col_end] .= vec(t_tuple) + end + end + return H +end + +code_n(rs::ShortenedMDS) = (2 ^ rs.m + 1 - 3) * rs.m + +code_k(rs::ShortenedMDS) = (2 ^ rs.m - 1 - 2 * rs.t) * rs.m diff --git a/test/runtests.jl b/test/runtests.jl index f274479a4..3f79429b2 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -65,6 +65,7 @@ end @doset "ecc_gottesman" @doset "ecc_reedmuller" @doset "ecc_bch" +@doset "ecc_shortenedmds" @doset "ecc_syndromes" @doset "ecc_throws" @doset "precompile" diff --git a/test/test_ecc_bch.jl b/test/test_ecc_bch.jl index 2885cd2ae..b73ac7eec 100644 --- a/test/test_ecc_bch.jl +++ b/test/test_ecc_bch.jl @@ -4,23 +4,21 @@ using QuantumClifford using QuantumClifford.ECC using QuantumClifford.ECC: AbstractECC, BCH, generator_polynomial using Nemo: ZZ, residue_ring, matrix, finite_field, GF, minpoly, coeff, lcm, FqPolyRingElem, FqFieldElem, is_zero, degree, defining_polynomial, is_irreducible +include("utils_test_ecc.jl") """ - To prove that `t`-bit error correcting BCH code indeed has minimum distance of at least `2 * t + 1`, it is shown that no `2 * t` or fewer columns of its binary parity check matrix `H` sum to zero. A formal mathematical proof can be found on pages 168 and 169 of Ch6 of Error Control Coding by Lin, Shu and Costello, Daniel. - The parameter `2 * t + 1` is usually called the designed distance of the `t`-bit error correcting BCH code. """ -function check_designed_distance(matrix, t) - n_cols = size(matrix, 2) - for num_cols in 1:2 * t - for i in 1:n_cols - num_cols + 1 - combo = matrix[:, i:(i + num_cols - 1)] - sum_cols = sum(combo, dims = 2) - if all(sum_cols .== 0) - return false # Minimum distance is not greater than `2 * t`. - end + +@testset "Testing designed distance of BCH codes" begin + m_cases = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] + for m in m_cases + for t in rand(1:m, 2) + d = 2 * t + @test check_designed_distance(parity_checks(BCH(m, t)), m, t, d, 0, 0) == true end end - return true # Minimum distance is at least `2 * t + 1`. end @testset "Testing properties of BCH codes" begin @@ -29,7 +27,6 @@ end n = 2 ^ m - 1 for t in rand(1:m, 2) H = parity_checks(BCH(m, t)) - @test check_designed_distance(H, t) == true # n - k == degree of generator polynomial, `g(x)` == rank of binary parity check matrix, `H`. mat = matrix(GF(2), parity_checks(BCH(m, t))) computed_rank = rank(mat) @@ -79,7 +76,8 @@ end results = [57 51 45 39 36 30 24 18 16 10 7] for (result, (m, t)) in zip(results, test_cases) + d = 2 * t @test code_k(BCH(m, t)) == result - @test check_designed_distance(parity_checks(BCH(m, t)), t) == true + @test check_designed_distance(parity_checks(BCH(m, t)), m, t, d, 0, 0) == true end end diff --git a/test/test_ecc_shortenedmds.jl b/test/test_ecc_shortenedmds.jl new file mode 100644 index 000000000..b53297a9b --- /dev/null +++ b/test/test_ecc_shortenedmds.jl @@ -0,0 +1,103 @@ +using Test +using LinearAlgebra +using Combinatorics +using QuantumClifford +using QuantumClifford.ECC +using QuantumClifford.ECC: AbstractECC, ShortenedMDS, generator_polynomial +using Nemo: finite_field, GF, FqFieldElem, FqPolyRingElem, coeff, is_zero, degree, matrix +include("utils_test_ecc.jl") + +@testset "Testing ShortenedMDS code" begin + +""" +- Employing `3-level` quantization of the channel bits and erasing entire symbols if any of their constituent bits are erased can improve the performance of RS codes. Shortened Maximum Distance Separable (MDS) codes have the following parameters - code length `(n)`, codesize `(k)` and minimum Hamming distance `(d)` represented by [n, k, d] as follows: [2 ^ (m) + 1 - 3, k, 2 ^ (m + 1) - 3 - k]. Thus, the designed minimum distance `d` is 2 ^ (m + 1) - s - k. Refer to chapter: 07, section: 03, pages: 172 to 175 [tomlinson2017error](@cite). +- The designed distance for binary expanded parity check matrix remains same as symbol based parity check matrix. According to [macwilliams1977theory](@cite), changing the basis `j` can increase the designed distance `(dmin)` of the resulting binary code. +""" + +@testset "Testing designed distance of ShortenedMDS codes" begin + m_cases = [3, 4, 5, 6, 7, 8] + for m in m_cases + for t in rand(1:m - 1, 2) + s_symbols = 3 # Refer to chapter: 07, section: 03, pages: 172 to 175 [tomlinson2017error](@cite). + k = (2 ^ m - 1 - 2 * t) * m + d = 2 ^ (m + 1) - s_symbols - k + @test check_designed_distance(parity_checks(ShortenedMDS(m, t)), m, t, d, 0, 0) == true + end + end +end + +@testset "Testing ShortenedMDS codes's properties" begin + m_cases = [3, 4, 5, 6, 7, 8] + for m in m_cases + for t in rand(1:m - 1, 2) + mat = matrix(GF(2), parity_checks(ShortenedMDS(m, t))) + computed_rank = rank(mat) + s_symbols = 3 # Refer to chapter: 07, section: 03, pages: 172 to 175 [tomlinson2017error](@cite). + k = (2 ^ m - 1 - 2 * t) * m + n = (2 ^ m + 1 - s_symbols) * m + @test computed_rank == n - k + end + end + + # Example `(H₁₅₀₋₇₅`) taken from Eq. 7.9 of pg. 175 of [tomlinson2017error](@cite). + @test size(parity_checks(ShortenedMDS(5, 8))) == (75, 150) + H = Matrix{Bool}(undef, 75, 150) + H = parity_checks(ShortenedMDS(5, 8)) + H₁₋₁ = [1 0 0 0 0 1 0 0 0 0 1 0 0 0 0; + 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0; + 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0; + 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0; + 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1; + 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0; + 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0; + 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1; + 0 0 0 1 0 0 0 0 0 1 1 0 1 0 0; + 0 0 0 0 1 1 0 1 0 0 0 1 0 1 0; + 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1; + 0 1 0 0 0 0 0 0 1 0 1 0 1 0 0; + 0 0 1 0 0 0 0 0 0 1 0 1 0 1 0; + 0 0 0 1 0 1 0 1 0 0 0 0 1 0 1; + 0 0 0 0 1 0 1 0 1 0 1 0 1 1 0; + 1 0 0 0 0 0 0 0 1 0 0 1 0 1 0; + 0 1 0 0 0 0 0 0 0 1 0 0 1 0 1; + 0 0 1 0 0 1 0 1 0 0 1 0 1 1 0; + 0 0 0 1 0 0 1 0 1 0 0 1 0 1 1; + 0 0 0 0 1 0 0 1 0 1 1 0 0 0 1] + H₁₋₂ = [1 0 0 0 0 1 0 1 1 1 0 1 1 0 1; + 0 1 0 0 0 1 1 1 1 1 1 0 0 1 0; + 0 0 1 0 0 1 1 0 1 1 0 1 0 0 1; + 0 0 0 1 0 1 1 0 0 1 1 0 0 0 0; + 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0] + H₁₋₃ = [1 0 0 0 0; + 0 1 0 0 0; + 0 0 1 0 0; + 0 0 0 1 0; + 0 0 0 0 1; + 1 0 0 1 0; + 0 1 0 0 1; + 1 0 0 0 0; + 0 1 0 0 0; + 0 0 1 0 0; + 1 1 0 1 0; + 0 1 1 0 1; + 1 0 0 1 0; + 0 1 0 0 1; + 1 0 0 0 0; + 1 0 0 1 1; + 1 1 1 0 1; + 1 1 0 1 0; + 0 1 1 0 1; + 1 0 0 1 0] + H₁₋₄ = [0 0 0 1 0; + 0 0 0 0 1; + 1 0 1 0 0; + 0 1 0 1 0; + 0 0 1 0 1] + + @test H[1:20, 1:15] == H₁₋₁ + @test H[71:75, 1:15] == H₁₋₂ + @test H[1:20, 146:150] == H₁₋₃ + @test H[71:75, 146:150] == H₁₋₄ +end + +end \ No newline at end of file diff --git a/test/test_ecc_throws.jl b/test/test_ecc_throws.jl index 19468e1ad..7f7dcff7d 100644 --- a/test/test_ecc_throws.jl +++ b/test/test_ecc_throws.jl @@ -1,9 +1,13 @@ using Test using QuantumClifford -using QuantumClifford.ECC: ReedMuller, BCH +using QuantumClifford.ECC: ReedMuller, BCH, ShortenedMDS @test_throws ArgumentError ReedMuller(-1, 3) @test_throws ArgumentError ReedMuller(1, 0) @test_throws ArgumentError BCH(2, 2) @test_throws ArgumentError BCH(3, 4) + +@test_throws ArgumentError ShortenedMDS(2, 1) +@test_throws ArgumentError ShortenedMDS(3, 10) +@test_throws ArgumentError ShortenedMDS(-2, 1) diff --git a/test/utils_test_ecc.jl b/test/utils_test_ecc.jl new file mode 100644 index 000000000..676e4cfb4 --- /dev/null +++ b/test/utils_test_ecc.jl @@ -0,0 +1,14 @@ +"""The designed distance of a classical linear code with parameters `[n, k, d]`, where `n` represents the code length, `k` denotes the code dimension, and `d` signifies the minimum Hamming distance. For polynomial codes, `t` indicates the degree of the generator polynomial, and `m` represents the extension degree for the finite Galois field `GF(2ᵐ)`.""" +function check_designed_distance(matrix, m, t, d, n, k) + n_cols = size(matrix, 2) + for num_cols in 1:d + for i in 1:n_cols - num_cols + 1 + combo = matrix[:, i:(i + num_cols - 1)] + sum_cols = sum(combo, dims = 2) + if all(sum_cols .== 0) + return false + end + end + end + return true +end