Skip to content
Snippets Groups Projects
Commit 393cc838 authored by florian.burgener's avatar florian.burgener
Browse files

Add comments

parent be40b6a3
No related branches found
No related tags found
No related merge requests found
import math import math
from numbers import Number
import itertools import itertools
import json
from typing import Tuple
def unicode_superscripts(value): def unicode_superscripts(number):
"""Convert a number into a string of unicode characters superscripts.
Args:
number (int): The number to convert.
Returns:
str: The unicode superscripts string.
"""
exponent_dict = {"0": "", "1": "¹", "2": "²", "3": "³", "4": "", "5": "", "6": "", "7": "", "8": "", "9": ""} exponent_dict = {"0": "", "1": "¹", "2": "²", "3": "³", "4": "", "5": "", "6": "", "7": "", "8": "", "9": ""}
return ("" if value < 0 else "") + "".join(exponent_dict[x] for x in str(abs(value))) return ("" if number < 0 else "") + "".join(exponent_dict[x] for x in str(abs(number)))
class Polynomial: class Polynomial:
"""Class for manipulating polynomials."""
def __init__(self, value=()): def __init__(self, value=()):
"""Creates an instance of Polynomial with a polynomial defined in a tuple.
Args:
value (tuple, optional): Polynomial defined in a tuple. Defaults to ().
Raises:
TypeError: The type of the parameter "value" is not a tuple.
"""
if not isinstance(value, tuple): if not isinstance(value, tuple):
raise TypeError('The "value" parameter is not of type tuple.') raise TypeError('The "value" parameter is not of type tuple.')
self.value = value self.value = value
def pass_x_throughout(self, x): def pass_x_throughout(self, x):
"""Evaluate the polynomial by passing x
Args:
x (int): The x to evaluate.
Returns:
int: The result of the evaluation.
"""
a = list(self.value) a = list(self.value)
sum = (a[len(a) - 1] * x) + a[len(a) - 2] sum = (a[len(a) - 1] * x) + a[len(a) - 2]
for i in reversed(range(len(a) - 2)): for i in reversed(range(len(a) - 2)):
sum = sum * x + a[i] sum = sum * x + a[i]
return sum return sum
def __add__(self, other): def __add__(self, other):
"""Add two polynomials.
Args:
other (Polynomial): The second polynomial to be added.
Returns:
Polynomial: The result of the addition.
"""
a = list(self.value) a = list(self.value)
b = list(other.value) b = list(other.value)
...@@ -45,35 +78,51 @@ class Polynomial: ...@@ -45,35 +78,51 @@ class Polynomial:
return Polynomial(tuple(c)) return Polynomial(tuple(c))
def __mul__(self, other): def __mul__(self, other):
"""Multiply two polynomials.
Args:
other (Polynomial): The second polynomial to be multiplied.
Returns:
Polynomial: The result of the multiplication.
"""
a = list(self.value) a = list(self.value)
b = list(other.value) b = list(other.value)
a_count = len(a) size = (len(a) - 1) + (len(b) - 1) + 1
b_count = len(b)
size = (a_count - 1) + (b_count - 1) + 1
c = [0] * size c = [0] * size
for i in range(a_count): for i in range(len(a)):
for j in range(b_count): for j in range(len(b)):
c[i + j] += a[i] * b[j] c[i + j] += a[i] * b[j]
return Polynomial(tuple(c)) return Polynomial(tuple(c))
def __mod__(self, other): def __mod__(self, other):
"""Apply a modulo on the polynomial.
Args:
other (int): The modulo to apply.
Returns:
Polynomial: The result of the modolu operation.
"""
a = list(self.value) a = list(self.value)
result = [0] * len(a) result = [0] * len(a)
for i in range(len(a)): for i in range(len(a)):
result[i] = a[i] % other result[i] = a[i] % other
for i in reversed(range(len(result))): for i in reversed(range(len(result))):
if result[i] == 0: if result[i] == 0:
del result[i] del result[i]
else: else:
break break
return Polynomial(tuple(result)) return Polynomial(tuple(result))
def __str__(self): def __str__(self):
"""Convert a polynomial into a string.
Returns:
str: The polynomial converts to a string.
"""
str_value = "" str_value = ""
for i, x in enumerate(reversed(self.value)): for i, x in enumerate(reversed(self.value)):
...@@ -92,67 +141,96 @@ class Polynomial: ...@@ -92,67 +141,96 @@ class Polynomial:
return str_value return str_value
def compute_bachet_bezout(a, b): def get_bezout_coefficients(a, b):
"""Find the Bézout coefficients of a and b.
Args:
a (int): The number a
b (int): The number b.
Returns:
tuple: Bézout coefficients.
"""
r = [a, b] r = [a, b]
x = [1, 0] x = [1, 0]
y = [0, 1] y = [0, 1]
q = [0, 0] q = [0, 0]
# Computing
i = 1 i = 1
while r[i] > 0: while r[i] > 0:
i += 1 i += 1
r.append(r[i - 2] % r[i - 1]) r.append(r[i - 2] % r[i - 1])
q.append(int(r[i - 2] / r[i - 1])) q.append(int(r[i - 2] / r[i - 1]))
if r[i] > 0: if r[i] > 0:
x.append(x[i - 2] - q[i] * x[i - 1]) x.append(x[i - 2] - q[i] * x[i - 1])
y.append(y[i - 2] - q[i] * y[i - 1]) y.append(y[i - 2] - q[i] * y[i - 1])
return x[-1], y[-1] return x[-1], y[-1]
def modular_inverse(a, n): def modular_inverse(a, n):
coefficients = compute_bachet_bezout(a, n) """Compute the modular inverse of a number a modolu n.
Args:
a (int): The number to reverse.
n (int): The modolu.
Returns:
int: The reversed number.
"""
coefficients = get_bezout_coefficients(a, n)
if a * coefficients[0] % n == 1: if a * coefficients[0] % n == 1:
return coefficients[0] % n return coefficients[0] % n
return None return None
def compute_lagrange_polynomial(points, prime_number): def compute_lagrange_polynomial(points, prime_number):
nb_points = len(points) """Compute the Lagrange polynomial passing through all points.
lagrange = Polynomial((0,))
# Create a polynomial for each points Args:
for i in range(nb_points): points (list): List of points.
poly_li = Polynomial((1,)) prime_number (int): The prime number.
divider = 1
# Compute the lagrange polynomial Returns:
for k in range(nb_points): Polynomial: The Lagrange polynomial passing through all points.
if k != i: """
dividend = Polynomial((-points[k][0], 1)) # x - value # Polynomial L(x)
L_polynomial = Polynomial((0,))
poly_li *= dividend # Create the Li(x) polynomial.
divider *= points[i][0] - points[k][0] for i, (xi, yi) in enumerate(points):
Li_polynomial = Polynomial((1,))
divider = modular_inverse(divider, prime_number) # For each point except the point at index i.
point_yi = points[i][1] for j, (xj, _) in enumerate(points):
poly_li = poly_li * Polynomial((divider,)) * Polynomial((point_yi,)) if j != i:
Li_polynomial *= Polynomial((-xj, 1))
Li_polynomial *= Polynomial((modular_inverse(xi - xj, prime_number),))
Li_polynomial *= Polynomial((yi,))
L_polynomial += Li_polynomial
return L_polynomial % prime_number
lagrange += poly_li
lagrange %= prime_number
return lagrange def reed_solomon(points, data_length, last_error_index, prime_number):
"""Applies the Reed-Solomon method to correct message errors.
Args:
points (list): List of points.
data_length (int): Data length.
last_error_index (int): The index of the last error.
prime_number (int): The prime number.
def reed_solomon(points, data_length, last_error_index, prime_number): Returns:
str: The corrected message.
"""
combination_length = data_length - len(points[:last_error_index]) combination_length = data_length - len(points[:last_error_index])
# Parse each combination of points possible (exclude the correct points) # Parse each combination of points possible (exclude the correct points)
for x in itertools.combinations(points[: last_error_index + 1], combination_length): for x in itertools.combinations(points[: last_error_index + 1], combination_length):
nb_valid_points = 0 nb_valid_points = 0
# Create a sublist of points with all corrects points and the current combination of points # Create a sublist of points with all corrects points and the current combination of points
sub_points = list(x) + points[last_error_index + 1:] sub_points = list(x) + points[last_error_index + 1 :]
# Create the lagrange polynomial with the sublist of points # Create the lagrange polynomial with the sublist of points
lagrange = compute_lagrange_polynomial(sub_points, prime_number) lagrange = compute_lagrange_polynomial(sub_points, prime_number)
...@@ -169,7 +247,7 @@ def reed_solomon(points, data_length, last_error_index, prime_number): ...@@ -169,7 +247,7 @@ def reed_solomon(points, data_length, last_error_index, prime_number):
# Verify if we have enough valid points, so it must be equal or higher than m + n points # Verify if we have enough valid points, so it must be equal or higher than m + n points
if nb_valid_points >= data_length + (len(points) - data_length) // 2: # // = euclid division if nb_valid_points >= data_length + (len(points) - data_length) // 2: # // = euclid division
# Decode the message # Decode the message
output = '' output = ""
for i in range(data_length): for i in range(data_length):
output += chr(lagrange.pass_x_throughout(i) % prime_number) output += chr(lagrange.pass_x_throughout(i) % prime_number)
...@@ -181,7 +259,6 @@ def reed_solomon(points, data_length, last_error_index, prime_number): ...@@ -181,7 +259,6 @@ def reed_solomon(points, data_length, last_error_index, prime_number):
def main(): def main():
message = {"data_length": 25, "last_error_index": 23, "prime_number": 401, "points": [67, 101, 38, 109, 101, 115, 133, 118, 103, 128, 62, 118, 97, 156, 116, 77, 49, 56, 86, 112, 171, 105, 176, 116, 115, 183, 30, 315, 368, 29, 352, 54, 333, 198, 139, 234, 321, 92, 5, 272, 396, 265, 397, 386, 229, 153, 276]} message = {"data_length": 25, "last_error_index": 23, "prime_number": 401, "points": [67, 101, 38, 109, 101, 115, 133, 118, 103, 128, 62, 118, 97, 156, 116, 77, 49, 56, 86, 112, 171, 105, 176, 116, 115, 183, 30, 315, 368, 29, 352, 54, 333, 198, 139, 234, 321, 92, 5, 272, 396, 265, 397, 386, 229, 153, 276]}
points = [(x, y) for x, y in enumerate(message["points"])] points = [(x, y) for x, y in enumerate(message["points"])]
print(points)
corrected_data = reed_solomon(points, message["data_length"], message["last_error_index"], message["prime_number"]) corrected_data = reed_solomon(points, message["data_length"], message["last_error_index"], message["prime_number"])
print(corrected_data) print(corrected_data)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment