Basic procedures for Cyclic, Hamming, Binary Reed-Muller, BCH, and Golay codes

  1. We construct the parity-check matrix and generator matrix of
    1. the cyclic code of length n over GF(p),
    2. the Hamming code over GF(p),
    3. the binary 1st order Reed-Muller code (which is length n=2m, dimension m+1, minimum distance 2m-1),
    4. the ternary (11,6)-Golay (which is perfect, minimum distance 5, and 2-error-correcting), and
    5. the binary (23,12)-Golay codes (which is perfect, distance 7, and 3-error-correcting). (The parity check matrix of the binary Hamming code is related to the generator matrix of the 1st order Reed-Muller code. Also, the (12,6)-Golay code and the (24,12)-Golay codes are also included.)
  2. We give a program which returns all the codewords in a code and all the codewords in its dual code, provided the prime p and the generator matrix are given. Another program uses this to give the minimum distanceof a code.
  3. We give a program which decodes a received word into a codeword using the nearest neighbor algorithm, provided the prime p, the distance d, and the generator matrix are given.
  4. We give a program for decoding binary and p-ary Hamming codes.
  5. We construct some BCH codes ("by hand").
  6. We give a program to determine if two binary linear codes are equivalent.
  7. We give a program to compute the automorphism group of a binary linear code.
There are several other procedures of minor importance which we leave to the partially documented code.

References:

  1. F. MacWilliams and N. Sloane, The theory of error-correcting codes , North-Holland, 1977
  2. R. Hill, A first course in coding theory , Oxford Univ. Press, 1986

There are also coding theory packages in GAP and MAGMA. See, for example, GAP3 and the Higman-Sims group (which uses the GAP coding theory package guava) and linear codes in MAGMA.

> restart;

> with(linalg): with(padic):

Warning, new definition for fibonacci

> read(`d:/maplestuff/codes/codes.mpl`);

`         Basic coding theory commands:`
` matrix_times_vector_modp, matrix_modp, golay12, g...
` golay23, golay24, golay12_check, golay11_check, `...
` golay23_check, golay24_check, check_matrix, gener...
` iscyclic, weight_codeword, weight_enumerator_vect...
` hamming_generator, hamming_weight, code_list, dua...
` decode, decode_hamming, RM_generator, weight_orde...
` weight_lexorder, isequivalent, isequivalent2, `
` automorphismgroup ... loaded. Last update 12-23-9...

Hamming codes

Parity check matrices of the binary Hamming code of length 2^2-1=3:

> hamming_check_binary(2);

matrix([[1, 0, 1], [0, 1, 1]])

> H:=hamming_check(3,5);
hamming_check_nonstandard(3,5);
Parity check matrices (in standard and non-standard form) of the 5-ary Hamming code of length (5^3-1)/(5-1)=31

H := matrix([[1, 0, 0, 1, 2, 3, 4, 1, 2, 3, 4, 0, 0...

matrix([[0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, ...

> H:=hamming_check_binary(3);
Parity check matrices of the binary Hamming code of length 2^3-1=7:

H := matrix([[1, 0, 0, 1, 1, 0, 1], [0, 1, 0, 1, 0,...

> H:=hamming_check(3,2);

H := matrix([[1, 0, 0, 1, 1, 0, 1], [0, 1, 0, 1, 0,...

A generator matrix of the binary Hamming code of length 3:

> hamming_generator(2,2);

matrix([[1, 1, 1]])

> G1:=hamming_generator(3,2);
A generator matrix of the binary Hamming code of length 7 (sometimes the transpose of this matrix is called the generator matrix):

G1 := matrix([[1, 1, 0, 1, 0, 0, 0], [1, 0, 1, 0, 1...

The dual code of this Hamming (7,4) code is a simplex (7,3) code.

> dual_code_list(G1,2);

[[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 1], [0, ...
[[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 1], [0, ...

>

> C1:=code_list(G1,2):
C1:=sort(C1,weight_order);
We can print out the list of all codewords, sorted according to weight:

C1 := [[0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 0, 0, 1, 0]...
C1 := [[0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 0, 0, 1, 0]...
C1 := [[0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 0, 0, 1, 0]...

> weight_enumerator_vector(G1,2);
There are 7 code words of weight 3, 7 code words of weight 4, and no code words of weights 1,2, 5 or 6.

[1, 0, 0, 7, 7, 0, 0, 1]

> weight_enumeration_polynomial(G1,2,x,y);
This is the weight enumerator polynomial of the Hamming (7,4,3)-code.

y^7+7*x^3*y^4+7*x^4*y^3+x^7

> min_distance(G1,2);
The minimum distance of the binary Hamming code of length 3

3

> v1:=[1,1,1,0,0,0,0];
matrix_times_vector_modp(H,v1,2);
This received word v1 has an error since H*v1 is non-zero.

v1 := [1, 1, 1, 0, 0, 0, 0]

[1, 1, 1]

> decode_hamming_binary(v1);
This command only works for binary Hamming codes.

[1, 1, 1, 0, 0, 0, 1]

> decode(v1,G1,2,3);
This command works for any linear code (2 is the prime residue, 3 is the distance of the code).

`corrected codeword: `, [1, 1, 1, 0, 0, 0, 1]

>

> H:=hamming_check(3,3);
G:=hamming_generator(3,3);
size_of_code:=3^(10);
parity check and generator matrix of Hamming ((p^k-1)/(p-1),(p^k-1)/(p-1)-k,3)-code with k=3,p=3

H := matrix([[1, 0, 0, 1, 2, 1, 2, 0, 0, 1, 2, 1, 2...

G := matrix([[2, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0...

size_of_code := 59049

> v1:=convert(row(H,1),list)+[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
matrix_times_vector_modp(H,v1,3);
This received word v1 has an error since H*v1 is non-zero

v1 := [2, 0, 0, 1, 2, 1, 2, 0, 0, 1, 2, 1, 2]

[1, 0, 0]

> decode_hamming(v1,3);

[1, 0, 0, 1, 2, 1, 2, 0, 0, 1, 2, 1, 2]

Reed-Muller codes

> G:=RM_generator(3);

G := matrix([[1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 1,...

This is a generator matrix of the binary 1st order Reed-Muller code of length 8. The matrix for the RM code of length 16 is:

> G_RM:=RM_generator(4);

G_RM := matrix([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1...

> C:=code_list(G_RM,2):
C_RM:=sort(C,weight_order);

C_RM := [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
C_RM := [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
C_RM := [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
C_RM := [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
C_RM := [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
C_RM := [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
C_RM := [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
C_RM := [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
C_RM := [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
C_RM := [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
C_RM := [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...

> nops(C);

32

Cyclic codes

One can test if g(x) is the generating polynomial of a cyclic code of length n over F_p using iscyclic(g(x),n,p)

> iscyclic(x+1,7,2);

true

> iscyclic(x^2+1,7,2);

false

>

> iscyclic(x^3+x+1,7,2);

true

Enter the generator polynomial of cyclic code and generator_matrix will return the corresponding generator matrix.

> G:=generator_matrix(x+1,7,2);

G := matrix([[1, 1, 0, 0, 0, 0, 0], [0, 1, 1, 0, 0,...

> min_distance(G,2);

2

The following generator matrix is the same size as that of the above Hamming code. Do they yield the same code?

> G2:=generator_matrix(x^3+x^2+1,7,2);

G2 := matrix([[1, 0, 1, 1, 0, 0, 0], [0, 1, 0, 1, 1...

> C2:=code_list(G2,2):
C2:=sort(C2,weight_order);

C2 := [[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 1, 1]...
C2 := [[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 1, 1]...
C2 := [[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 1, 1]...

> evalb(C1=C2);
This cyclic code generated by x^3+x^2+1 is not the Hamming code of length 7 and distance 3, over F_2, given above.

false

> min_distance(G2,2);

3

There is some built-in error checking in generator_matrix :

> generator_matrix(x^2+1,7,2);

Error, (in generator_matrix) the polynomial doesn't generate a cyclic code

Enter the generator polynomial of cyclic code and check_matrix will return the corresponding parity check matrix.

> H:=check_matrix(x^3+x^2+1,7,2);

H := matrix([[1, 1, 1, 0, 1, 0, 0], [0, 1, 1, 1, 0,...

> v1:=[1,1,1,1,0,0,0];
matrix_times_vector_modp(H,v1,2);
The word v1 is not in the cyclic code generated by x^3+x^2+1 since H*v1 is non-zero.

v1 := [1, 1, 1, 1, 0, 0, 0]

[1, 1, 0]

> decode(v1,G2,2,2);

`corrected codeword: `, [1, 0, 1, 1, 0, 0, 0]

> check_matrix(x^3+y^2+1,7,2);
check_matrix(x^3+1,7,2);
check_matrix has some built-in error checking

Error, (in check_matrix) g should be a polynomial in x

Error, (in check_matrix) the polynomial doesn't generate a cyclic code

>

Golay codes

The generator matrix for the ternary (12,6) code:

> G:=golay12();

G := matrix([[1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1], ...

> min_distance(G,3);
This is very time-consuming on some machines (about 15 seconds on a 300Mhz pentium).

6

The parity check matrix for the ternary (12,6) code:

> H:=golay_check12();

H := matrix([[0, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0], ...

> v1:=[1, 2, 2, 2, 2, 1, 0, 1, 0, 0, 1, 2];
matrix_times_vector_modp(H,v1,3);
v1 is not a codeword in the (12,6)-Golay code. It has only 1 error (in the first position).

v1 := [1, 2, 2, 2, 2, 1, 0, 1, 0, 0, 1, 2]

[0, 1, 1, 1, 1, 1]

> decode(v1,G,3,5);
The decoding:

`corrected codeword: `, [2, 2, 2, 2, 2, 1, 0, 1, 0,...

> v2:=[1, 1, 2, 2, 2, 1, 0, 1, 0, 0, 1, 2];
decode(v2,G,3,5);
Another example, with 2 errors.

v2 := [1, 1, 2, 2, 2, 1, 0, 1, 0, 0, 1, 2]

`corrected codeword: `, [2, 2, 2, 2, 2, 1, 0, 1, 0,...

>

The generator matrix for the perfect ternary (11,6) code:

> G:=golay11();

G := matrix([[1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1], [0,...

> min_distance(G,3);
This is very time-consuming.

5

The parity check matrix for the ternary (11,6) code:

> H:=golay_check11();

H := matrix([[2, 0, 2, 1, 1, 2, 1, 0, 0, 0, 0], [2,...

The generator matrix for the perfect binary (23,12) code:

> G:=golay23();

G := matrix([[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...

The parity check matrix for the perfect binary (23,12) code:

> H:=golay_check23();

H := matrix([[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1...

> v1:=[0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1];
matrix_times_vector_modp(H,v1,2);
v1 is not a codeword in the (23,12)-Golay code. It has only 1 error (in the first position).

v1 := [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,...

[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

> decode(v1,G,2,7);
This is time-consuming to decode than the above Hamming code since the Golay code is larger.

`corrected codeword: `, [1, 0, 0, 0, 0, 0, 0, 0, 0,...

> v2:=[0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0];
matrix_times_vector_modp(H,v2,2);
decode(v2,G,2,7);
This "string" has 3 errors

v2 := [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,...

[0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0]

`corrected codeword: `, [1, 0, 0, 0, 0, 0, 0, 0, 0,...

> G:=golay24();
The generator matrix for the (24,12)-Golay code

G := matrix([[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...

> H:=golay_check24();
The parity check matrix for the (24,12)-Golay code.

H := matrix([[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1...

> coldim(G);coldim(H);

24

24

BCH codes

We shall construct by hand some BCH codes. A BCH code is a cyclic code which included the binary Hamming codes as a special case.

To construct a (binary, narrow) BCH code, you must have a primitive element alpha of degree k over F=GF(2). You must know the minimal polynomials of a sequence of powers of alpha: alpha, alpha^2, ..., alpha^(2t). Take the lcm of these. This new polynomial is the generating polynomial of the BCH code. It has minimum distance 2t+1.

> ### WARNING: persistent store makes one-argument readlib obsolete
readlib(lattice):
minpoly_lattice:=minpoly;
#linalg has a minpoly command too
with(numtheory):
### WARNING: persistent store makes one-argument readlib obsolete
readlib(GF):

minpoly_lattice := minpoly

Warning, new definition for order

>

> f:=x^4+x+1;
alias(beta=RootOf(f)):
Factor(f) mod 2;
Factor(f,beta) mod 2;
Roots(f,beta) mod 2;
for i from 1 to 19 do
pp[i]:=unapply(minpoly_lattice(beta^i,4),_X):
print(beta^i,pp[i](x));
od:

f := x^4+x+1

x^4+x+1

(x+beta+1)*(x+beta^2+1)*(x+beta)*(x+beta^2)

[[beta^2+1, 1], [beta, 1], [beta+1, 1], [beta^2, 1]...

beta, x^4+x+1

beta^2, 1-x+2*x^2+x^4

beta^3, 1+x+3*x^2+3*x^3+x^4

beta^4, 1+3*x+6*x^2+4*x^3+x^4

beta^5, 1-4*x+5*x^2+x^4

beta^6, 1+5*x+5*x^2-3*x^3+x^4

beta^7, 1-6*x+14*x^2-7*x^3+x^4

beta^8, 1+3*x+14*x^2-4*x^3+x^4

beta^9, 1+x+21*x^2+3*x^3+x^4

beta^10, 1-6*x+27*x^2+10*x^3+x^4

beta^11, 1+12*x+44*x^2+11*x^3+x^4

beta^12, 1-15*x+57*x^2+x^3+x^4

beta^13, 1+14*x+78*x^2-13*x^3+x^4

beta^14, 1-8*x+114*x^2-21*x^3+x^4

beta^15, 1-4*x+158*x^2-12*x^3+x^4

beta^16, 1+19*x+222*x^2+12*x^3+x^4

beta^17, 1-33*x+306*x^2+34*x^3+x^4

beta^18, 1+41*x+437*x^2+33*x^3+x^4

beta^19, x^4

> GenPoly:=x->Lcm(seq(pp[j](x),j=1..4)) mod 2:
GenPoly(x);
Quo(x^(15)-1,GenPoly(x),x) mod 2;
iscyclic(GenPoly(x),15,2);

x^4+1+x^6+x^7+x^8

x^7+x^6+x^4+1

true

In other words, GenPoly(x) is indeed the generating polynomial for some cyclic code over F_2.

> G:=generator_matrix(GenPoly(x),15,2);
linalg[rowdim](G);
linalg[coldim](G);
H:=check_matrix(GenPoly(x),15,2);
linalg[rowdim](H);
linalg[coldim](H);
This code is 2-error correcting.

G := matrix([[1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0...

7

15

H := matrix([[1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0...

8

15

>

> f:=x^6+x^3+1;
alias(beta=RootOf(f)):
Irreduc(f) mod 2;
Factor(f,beta) mod 2;
Roots(f,beta) mod 2;
for i from 1 to 12 do
pp[i]:=unapply(minpoly_lattice(beta^i,6),_X):
print(beta^i,pp[i](x));
od:

f := x^6+x^3+1

true

(x+beta^4+beta)*(x+beta^4)*(x+beta^5)*(x+beta)*(x+b...

[[beta^5, 1], [beta^4, 1], [beta, 1], [beta^4+beta,...

beta, x^6+x^3+1

beta^2, x^6+x^3+1

beta^3, 1+x+x^2

beta^4, x^6+x^3+1

beta^5, x^6+x^3+1

beta^6, 1+x+x^2

beta^7, x^6+x^3+1

beta^8, x^6+x^3+1

beta^9, -1+x

beta^10, x^6+x^3+1

beta^11, x^6+x^3+1

beta^12, 1+x+x^2

> GenPoly:=x->Lcm(seq(pp[j](x),j=1..8)) mod 2:
GenPoly(x);
iscyclic(GenPoly(x),63,2);

x^6+x^7+x^8+x^3+x^4+x^5+1+x+x^2

true

In other words, GenPoly(x) is indeed the generating polynomial for some cyclic code over F_2. This code is 4-error correcting.

> G:=generator_matrix(GenPoly(x),63,2):
linalg[rowdim](G);
linalg[coldim](G);
H:=check_matrix(GenPoly(x),63,2);

55

63

H := matrix([[1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0...
H := matrix([[1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0...
H := matrix([[1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0...
H := matrix([[1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0...
H := matrix([[1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0...
H := matrix([[1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0...
H := matrix([[1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0...
H := matrix([[1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0...
H := matrix([[1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0...

>

When are linear codes equivalent?

We must load the group21_v5.mpl package

(see http://web.usna.navy.mil/~wdj/symm_gp.htm)

> with(combinat):
with(group):
read(`d:/maplestuff/group/group21_v5.mpl`);

Warning, new definition for fibonacci

`   Basic group theory commands:   `

`gp_elements, elements_order, conjugation, conjugac...

`conjugacy_classes_reps, gp_table, abs_gp_table, mu...

`perm_value, perm_sign, permute_vector_left, permut...

`mult_sets, is_subset, is_sublist, left_coset_reps,...

`cartesian_product, cartesian_power, conj_type, con...

`innerprod, is_reducible, array_to_disjcyc, list_to...

`list_to_array ... loaded. group21_v5.mpl MAPLEV5, ...

>

> G1:=hamming_generator(3,2);
C1:=code_list(G1,2):
C1:=sort(C1,weight_lexorder);
Gausselim(G1) mod 2;
G2:=generator_matrix(x^3+x^2+1,7,2);
C2:=code_list(G2,2):
C2:=sort(C2,weight_lexorder);

G1 := matrix([[1, 1, 0, 1, 0, 0, 0], [1, 0, 1, 0, 1...

C1 := [[0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 0]...
C1 := [[0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 0]...
C1 := [[0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 0]...

matrix([[1, 1, 0, 1, 0, 0, 0], [0, 1, 1, 1, 1, 0, 0...

G2 := matrix([[1, 0, 1, 1, 0, 0, 0], [0, 1, 0, 1, 1...

C2 := [[0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 1, 0]...
C2 := [[0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 1, 0]...
C2 := [[0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 1, 0]...

The following program (on a 350Mz pentium II) returns true , if the binary linear code C1 with generator matrix G1 is equivalent to the binary linear code C2 with gen matrix G2 plus an associated column permutation for the second matrix, and returns false otherwise.

> t0:=time():
isequivalent(G1,G2);
time()-t0;

`Uses group21_v5.mpl. Please be patient for output ...

[true, [[4, 5, 7, 6]]]

18.431

The following program does the same thing as the program above but uses a different algorithm. (Usually this second algorithm seems to be faster but obviously not in this case.)

> t0:=time():
isequivalent2(G1,G2);
time()-t0;

`Uses group21_v5.mpl. Please be patient for output ...

[true, [[1, 2, 5, 3, 4], [6, 7]]]

41.894

Next, we compute the automorphism group of a binary linear code.

> G1:=matrix([[1,1,0,1,0],[1,1,1,0,1],[1,1,0,1,0]]);

G1 := matrix([[1, 1, 0, 1, 0], [1, 1, 1, 0, 1], [1,...

> t0:=time():
automorphismgroup(G1);
time()-t0;

`Uses group21_v5.mpl. Please be patient for output ...

[[], [[3, 5]], [[1, 2]], [[1, 2], [3, 5]]]

3.815

>


Based on the worksheet codes.mws and the maple package codes.mpl. Maple7 version: codes_v7.mpl. Created wdj,6-2-98, last updated 8-2001.