AGRL 112: Assignment 10 (Error Correcting Codes (ECC))
(IIT Delhi - Abu Dhabi)
1. An $(n, k, d)$ Error-Correcting Code
1.1 Messages and codewords
Imagine you want to send a short piece of data, for example, a list of $k$ numbers. We will call this list the message and write it as: $$m = (m_1, m_2, ..., m_k).$$ An error-correcting code takes your message $m$ and transforms it into a longer list $$c = (c_1, c_2, ..., c_n),$$ called a codeword. The error correcting code consists of all these codewords. Here:- $k$ = length of the original message,
- $n$ = length of the encoded message (the codeword)
- typically $n > k$, so we add some extra symbols (often called "parity" or "redundancy")
1.2 Hamming distance between codewords
To talk about error correction, we need a way to measure how "different" two codewords are. The Hamming distance between two codewords of length $n$, $$c = (c_1, ..., c_n), c' = (c_1', ..., c_n'),$$ is the number of positions where they differ: $$dist(c, c') = |\{i | c_i \neq c_i'\}|.$$ Example (with symbols being small integers): $$c = (5, 10, 3, 3, 0), c' = (5, 9, 3, 3, 2).$$ They differ in positions 1 (10 vs 9) and position 4 (0 vs 2), so $$dist(c, c') = 2.$$1.3 The parameter $d$: minimum distance
The minimum distance $d$ of a code $\mathcal{C}$ is: $$d = \min_{c, c' \in \mathcal{C}, c\neq c'} dist(c, c'),$$ the smallest Hamming distance between any two distinct codewords of the code. Intuitively:- If $d$ is large, codewords are "far apart" and it is harder for errors to turn one valid codeword into another.
- If $d$ is small, codewords are too close and even a few errors may cause confusion
1.4 What does $(n, k, d)$ mean?
An $(n, k, d)$ code is an error-correcting code with:- codeword length $n$,
- message length $k$,
- minimum distance $d$.
- Error detection: An $(n, k, d)$ code can always detect up to $d−1$ symbol errors in a codeword.
- If at most $d−1$ symbols are changed, the received word cannot be equal to another valid codeword.
- Error correction:An $(n, k, d)$ code can always correct up to $$t = \lfloor \frac{d-1}{2}\rfloor$$ symbol errors.
- If at most $t$ symbols are wrong, there is a unique codeword that is closest to the received word, and we can recover it.
2. Arithmetic Modulo a Prime Number
The Reed-Solomon codes used in QR codes use more advanced math (finite fields of size $2^8$), but this is not necessary for us. Instead, we will work with simple integers using the modulo operation.2.1 Integers modulo 251
We will work with the numbers $$\{0, 1, 2, ..., 250\}$$ and we will always do arithmetic modulo 251.2.2 Operations you will implement
In your code, implement the following functions (or their equivalents):P = 251 # the prime modulus
def f_add(a, b):
# return (a + b) mod 251
def f_sub(a, b):
# return (a - b) mod 251
def f_mul(a, b):
# return (a * b) mod 251
def f_inv(a):
# return the multiplicative inverse of a (mod 251)
# i.e., a number x such that (a * x) mod 251 == 1
def f_div(a, b):
# return a * f_inv(b) (mod 251)
Cell In[1], line 6 def f_sub(a, b): ^ IndentationError: expected an indented block
3. Reed-Solomon Codes over Integers Modulo 251
We will build a simple Reed–Solomon code with parameters $$n = 15, k = 11.$$ So each message will have $k = 11$ symbols, and each codeword will have $n = 15$ symbols. There are $n−k = 4$ extra symbols, which will help with error detection/correction.3.1 Polynomials with coefficients mod 251
We will represent a polynomial by a list of its coefficients. For example, $$p(x) = 3x^2 + 5x + 7$$ can be represented as: $$[3, 5, 7].$$ You will implement the following functions:def poly_add(p, q):
"""
Add two polynomials with coefficients mod 251.
Return a new polynomial.
"""
def poly_scale(p, a):
"""
Multiply polynomial p by scalar a (mod 251).
"""
def poly_mul(p, q):
"""
Multiply two polynomials with coefficients mod 251.
"""
def poly_div(dividend, divisor):
"""
Polynomial long division: return (quotient, remainder)
such that dividend = quotient * divisor + remainder.
All arithmetic is mod 251.
"""
All these functions should use f_add, f_sub, f_mul, f_div from Section 2.
3.2 Encoding messages
In Reed-Solomon codes, the message is interpreted as a degree $k−1$ polynomial. For instance, if the message is $(3, 212, 43)$, then we will interpret this as the polynomial $p(x) = 3x^2 + 212x + 43$ (everything is modulo 251). To encode this message, choose $n$ distinct integers modulo 251 as evaluation points. For this assignment you must use: $$x_1 = 1, x_2 = 2, ..., x_n = n.$$ (You may assume $n < 251$, so all evaluation points are distinct.)Given the message polynomial $P(x)$, the Reed–Solomon codeword is: $$c = (p(1), p(2), . . . , p(n)) \textrm{ all taken mod 251}.$$ This is the entire encoding process.
3.3 Why this is an error correcting code
A fundamental fact from algebra (you do not need to prove it) is:Fact: A degree $(k−1)$ polynomial is uniquely determined by its values at any $k$ distinct points.
Therefore, even if many of the $n$ values $(P(1), ..., P(n))$ are corrupted, as long as at least $k$ of them are still correct, the original polynomial $P(x)$ can be reconstructed. This is why evaluation-based Reed–Solomon codes have minimum distance: $$d = n-k+1,$$ and can correct up to $$t = \lfloor \frac{n-k}{2} \rfloor$$ symbol errors.
3.4 Error detection
Given a received vector $$(y_1, y_2, ..., y_n),$$ we can detect errors by checking whether these values lie on some polynomial of degree $\leq k−1$. In this assignment, you will do this using a simple and direct test:- Try to interpolate a degree-$\leq (k−1)$ polynomial $Q(x)$ that fits all $n$ points.
- If interpolation succeeds (the points lie exactly on some polynomial), no errors occurred.
- If interpolation fails, then an error is present.
def interpolate(points):
"""
Given a list of (x, y) pairs with x distinct,
return the coefficients of the unique polynomial Q(x)
of degree <= k-1 that fits all the points,
OR return None if no such polynomial exists.
"""
3.5 Single-error correction
To keep complexity reasonable, you are only required to correct one erroneous symbol. Given received values $$(y_1, ..., y_n),$$ your task is to find the location and value of the single error by brute force. You will implement:def rs_correct_single_error(y, n, k):
"""
Attempt to correct a single corrupted value in y.
Try every position i and every possible replacement value v,
and check whether the modified vector fits a degree <= k-1 polynomial.
Return (corrected_codeword, polynomial_coeffs) if successful.
Return None if no single error can explain the received vector.
"""
Here is the sketch of the algorithm:
- For each position $i \in \{1, ..., n\}$ and each candidate value $v$ in $\{0, ..., 250\}$:
- Replace $y_i$ by $v$.
- Try interpolating a polynomial of degree-$\leq k−1$ that fits all $n$ points.
- If interpolation succeeds:
- Report success
- return the corrected codeword and the recovered message.
Optional task: Use the Reed-Solomon code to implement your own QR code. Depending on the amount of noise you want to tolerate, you would need to increase the length of your codeword.