From 0d93eb43d37086343e34301f012e6a7e8ac6fd11 Mon Sep 17 00:00:00 2001 From: Trance-0 <60459821+Trance-0@users.noreply.github.com> Date: Mon, 27 Oct 2025 10:59:25 -0500 Subject: [PATCH] updates --- content/CSE5313/CSE5313_L2.md | 34 +- content/CSE5313/Exam_reviews/CSE5313_E1.md | 356 +++++++++++++++++++++ content/CSE5313/_meta.js | 1 + 3 files changed, 383 insertions(+), 8 deletions(-) create mode 100644 content/CSE5313/Exam_reviews/CSE5313_E1.md diff --git a/content/CSE5313/CSE5313_L2.md b/content/CSE5313/CSE5313_L2.md index ec8d7c0..c0968ec 100644 --- a/content/CSE5313/CSE5313_L2.md +++ b/content/CSE5313/CSE5313_L2.md @@ -267,11 +267,9 @@ Hamming distance is a metric. ### Level of error handling -error detection - -erasure correction - -error correction +- error detection +- erasure correction +- error correction Erasure: replacement of an entry by $*\not\in F$. @@ -283,11 +281,27 @@ Example: If $d_H(\mathcal{C})=d$. Theorem: If $d_H(\mathcal{C})=d$, then there exists $f:F^n\to \mathcal{C}\cap \{\text{"error detected"}\}$. that detects every patter of $\leq d-1$ errors correctly. -\* track lost *\ +- That is, we can identify if the channel introduced at most $d-1$ errors. +- No decoding is needed. Idea: -Since $d_H(\mathcal{C})=d$, one needs $\geq d$ errors to cause "confusion$. +Since $d_H(\mathcal{C})=d$, one needs $\geq d$ errors to cause "confusion". + +
+Proof + +The function +$$ +f(y)=\begin{cases} +y\text{ if }y\in \mathcal{C}\\ +\text{"error detected"} & \text{otherwise} +\end{cases} +$$ + +will only fails if there are $\geq d$ errors. + +
#### Erasure correction @@ -295,7 +309,11 @@ Theorem: If $d_H(\mathcal{C})=d$, then there exists $f:\{F^n\cup \{*\}\}\to \mat Idea: -\* track lost *\ +Suppose $d=4$. + +If $4$ erasures occurred, there might be two possible codewords $c,c'\in \mathcal{C}$. + +If $\leq 3$ erasures occurred, there is only one possible codeword $c\in \mathcal{C}$. #### Error correction diff --git a/content/CSE5313/Exam_reviews/CSE5313_E1.md b/content/CSE5313/Exam_reviews/CSE5313_E1.md new file mode 100644 index 0000000..48abd57 --- /dev/null +++ b/content/CSE5313/Exam_reviews/CSE5313_E1.md @@ -0,0 +1,356 @@ +# CSE 5313 Exam 1 review + +## Basic math + +```python +class PrimeField: + def __init__(self, p: int, value: int = 0): + if not utils.prime(p): + raise ValueError("p must be a prime number") + if value >= p or value < 0: + raise ValueError("value must be integers in the range [0, p)") + self.p = p + self.value = value + + def field_check(func): + def wrapper(self: 'PrimeField', other: 'PrimeField') -> 'PrimeField': + if self.p != other.p: + raise ValueError("Fields must have the same prime modulus") + return func(self, other) + return wrapper + + def additive_inverse(self) -> 'PrimeField': + return PrimeField(self.p, self.p - self.value) + + def multiplicative_inverse(self) -> 'PrimeField': + # done by Fermat's little theorem + return PrimeField(self.p, pow(self.value, self.p - 2, self.p)) + + def next_value(self) -> 'PrimeField': + return self + PrimeField(self.p, 1) + + @field_check + def __add__(self, other: 'PrimeField') -> 'PrimeField': + return PrimeField(self.p, (self.value + other.value) % self.p) + + @field_check + def __sub__(self, other: 'PrimeField') -> 'PrimeField': + return PrimeField(self.p, (self.value - other.value) % self.p) + + @field_check + def __mul__(self, other: 'PrimeField') -> 'PrimeField': + return PrimeField(self.p, (self.value * other.value) % self.p) + + @field_check + def __truediv__(self, other: 'PrimeField') -> 'PrimeField': + return PrimeField(self.p, (self.value * other.multiplicative_inverse().value)%self.p) + + def __pow__(self, other: int) -> 'PrimeField': + # no field check for power operation + return PrimeField(self.p, pow(self.value, other, self.p)) + + @field_check + def __eq__(self, other: 'PrimeField') -> bool: + return self.value == other.value + + @field_check + def __ne__(self, other: 'PrimeField') -> bool: + return self.value != other.value + + @field_check + def __lt__(self, other: 'PrimeField') -> bool: + return self.value < other.value + + @field_check + def __le__(self, other: 'PrimeField') -> bool: + return self.value <= other.value + + @field_check + def __gt__(self, other: 'PrimeField') -> bool: + return self.value > other.value + + @field_check + def __ge__(self, other: 'PrimeField') -> bool: + return self.value >= other.value + + def __str__(self) -> str: + return f"PrimeField({self.p}, {self.value})" +``` + +For field extension. + +```python +class Polynomial(): + # strict constructor + def __init__(self, p: int, coefficients: list[PrimeField]=[]): + if len(coefficients) == 0: + # no empty list is allowed + coefficients = [PrimeField(p, 0)] + if not utils.prime(p): + raise ValueError("p must be a prime number") + self.p = p + for coefficient in coefficients: + if not isinstance(coefficient, PrimeField) or coefficient.p != p: + raise ValueError("coefficients must be in the same field") + self.coefficients = coefficients + self.remove_leading_zero_coefficients() + + # lazy constructor + @classmethod + def from_integers(cls, p: int, coefficients: list[int]) -> 'Polynomial': + # coefficients test + for coefficient in coefficients: + if 0 > coefficient or coefficient >= p: + raise ValueError("coefficients must be integers in the range [0, p)") + return cls(p, [PrimeField(p, coefficient) for coefficient in coefficients]) + + def __len__(self) -> int: + return len(self.coefficients) + + def degree(self) -> int: + return len(self.coefficients) - 1 + + def evaluate(self, x: PrimeField) -> PrimeField: + if x.p != self.p: + raise ValueError("x must be in the same field as the polynomial") + return sum([(x ** i) * coefficient for i, coefficient in enumerate(self.coefficients)], PrimeField(self.p, 0)) + + def padding_coefficients(self, degree: int) -> None: + if degree < self.degree(): + raise ValueError("degree must be greater than or equal to the current degree") + self.coefficients += [PrimeField(self.p, 0) for _ in range(degree - self.degree())] + + def remove_leading_zero_coefficients(self) -> None: + while self.degree() > 0 and self.coefficients[self.degree()].value == 0: + self.coefficients.pop() + + def field_check(func): + def wrapper(self: 'Polynomial', other: 'Polynomial') -> 'Polynomial': + if self.p != other.p: + raise ValueError("Fields must have the same prime modulus") + return func(self, other) + return wrapper + + def is_constant(self) -> bool: + return self.degree() == 0 + + def next_value(self) -> 'Polynomial': + # function enumerate all possible polynomials, degree may increase by 1 + new_coefficients = self.coefficients.copy() + # do list addition + pt=0 + new_coefficients[pt] = new_coefficients[pt].next_value() + while pt < self.degree() and new_coefficients[pt] == PrimeField(self.p, 0): + pt += 1 + new_coefficients[pt] = new_coefficients[pt].next_value() + if pt == self.degree(): + new_coefficients.append(PrimeField(self.p, 1)) + return Polynomial(self.p, new_coefficients) + + def is_irreducible(self) -> bool: + # brute force check all possible divisors + if self.is_constant(): + return False + # start from first non-constant coefficient + divisor = self.from_integers(self.p, [0,1]) + while divisor.degree() < self.degree(): + # debug + # print(f"{self}, enumerate divisor: {divisor.as_integers()}") + if self % divisor == self.from_integers(self.p, [0]): + # debug + # print(f"divisor: {divisor}, self: {self}") + return False + divisor = divisor.next_value() + return True + + @field_check + def __add__(self, other: 'Polynomial') -> 'Polynomial': + padding_degree = max(self.degree(), other.degree()) + self.padding_coefficients(padding_degree) + other.padding_coefficients(padding_degree) + new_coefficients = [self.coefficients[i] + other.coefficients[i] for i in range(padding_degree + 1)] + return Polynomial(self.p, new_coefficients) + + @field_check + def __sub__(self, other: 'Polynomial') -> 'Polynomial': + padding_degree = max(self.degree(), other.degree()) + self.padding_coefficients(padding_degree) + other.padding_coefficients(padding_degree) + new_coefficients = [self.coefficients[i] - other.coefficients[i] for i in range(padding_degree + 1)] + return Polynomial(self.p, new_coefficients) + + @field_check + def __mul__(self, other: 'Polynomial') -> 'Polynomial': + new_coefficients = [PrimeField(self.p, 0) for _ in range(self.degree() + other.degree() + 1)] + for i in range(self.degree() + 1): + for j in range(other.degree() + 1): + new_coefficients[i + j] += self.coefficients[i] * other.coefficients[j] + return Polynomial(self.p, new_coefficients) + + def __long_division__(self, other: 'Polynomial') -> 'Polynomial': + if self.degree() < other.degree(): + return self.from_integers(self.p, [0]), self + quotient = self.from_integers(self.p, [0]) + remainder = self + while remainder.degree() != 0 and remainder.degree() >= other.degree(): + # debug + # print(f"remainder: {remainder}, remainder degree: {remainder.degree()}, other: {other}, other degree: {other.degree()}") + # reduce to primitive operation + division_result = (remainder.coefficients[remainder.degree()] / other.coefficients[other.degree()]).value + division_polynomial = self.from_integers(self.p,[0]* (remainder.degree() - other.degree()) + [division_result]) + quotient += division_polynomial + # degree automatically adjusted + remainder = remainder - (division_polynomial * other) + return quotient, remainder + + @field_check + def __truediv__(self, other: 'Polynomial') -> 'Polynomial': + return Polynomial(self.p, self.__long_division__(other)[0].coefficients) + + @field_check + def __mod__(self, other: 'Polynomial') -> 'Polynomial': + return Polynomial(self.p, self.__long_division__(other)[1].coefficients) + + def __pow__(self, other: int) -> 'Polynomial': + # you many need better algorithm to speed up this operation + if other == 0: + return Polynomial(self.p, [PrimeField(self.p, 1)]) + if other == 1: + return self + # fast exponentiation + if other % 2 == 0: + return (self * self) ** (other // 2) + return self * (self * self) ** ((other - 1) // 2) + + @field_check + def __eq__(self, other: 'Polynomial') -> bool: + return self.degree() == other.degree() and all(self.coefficients[i] == other.coefficients[i] for i in range(self.degree() + 1)) + + @field_check + def __ne__(self, other: 'Polynomial') -> bool: + return self.degree() != other.degree() or any(self.coefficients[i] != other.coefficients[i] for i in range(self.degree() + 1)) + + def __str__(self) -> str: + string_arr = [f"{coefficient.value}x^{i}" for i, coefficient in enumerate(self.coefficients) if coefficient.value != 0] + return f"Polynomial over GF({self.p}): {' + '.join(string_arr)}" + + def as_integers(self) -> list[int]: + return [coefficient.value for coefficient in self.coefficients] + + def as_number(self) -> int: + return sum([coefficient.value * self.p ** i for i, coefficient in enumerate(self.coefficients)]) +``` +```python +class FiniteField(): + def __init__(self, p: int, n: int = 1, value: Polynomial = None, irreducible_polynomial: Polynomial = None): + # set default value to zero polynomial + if value is None: + value = Polynomial.from_integers(p, [0]) + if value.degree() >= n: + raise ValueError("Value must be a polynomial of degree less than n") + if not utils.prime(p): + raise ValueError("p must be a prime number") + if n<1: + raise ValueError("n must be non-negative") + # auto set irreducible polynomial + if irreducible_polynomial is not None: + if not irreducible_polynomial.is_irreducible(): + raise ValueError("Irreducible polynomial is not irreducible") + else: + irreducible_polynomial = Polynomial.from_integers(p, [0]*(n) + [1]) + while not irreducible_polynomial.is_irreducible(): + irreducible_polynomial = irreducible_polynomial.next_value() + self.p = p + self.n = n + self.value = value + self.irreducible_polynomial = irreducible_polynomial + + @classmethod + def from_integers(cls, p: int, n: int, coefficients: list[int], irreducible_polynomial: Polynomial = None) -> 'FiniteField': + return cls(p, n, Polynomial.from_integers(p, coefficients), irreducible_polynomial) + + def additive_inverse(self) -> 'FiniteField': + coefficients = [-coefficient for coefficient in self.value.coefficients] + return FiniteField(self.p, self.n, Polynomial(self.p, coefficients), self.irreducible_polynomial) + + def multiplicative_inverse(self) -> 'FiniteField': + # via Fermat's little theorem + return FiniteField(self.p, self.n, self.value ** ((self.p**self.n) - 2) % self.irreducible_polynomial, self.irreducible_polynomial) + + def get_subfield(self) -> list['FiniteField']: + subfield = [ + FiniteField(self.p, self.n, Polynomial.from_integers(self.p, [0]), self.irreducible_polynomial), + FiniteField(self.p, self.n, Polynomial.from_integers(self.p, [1]), self.irreducible_polynomial) + ] + current_element = self + for _ in range(0, (self.p**self.n) - 1): + if current_element in subfield: + break + subfield.append(current_element) + current_element = current_element * self + return subfield + + def is_primitive(self) -> bool: + # check if the element is a primitive element from definition + subfield = self.get_subfield() + return len(subfield) == (self.p**self.n) + + def next_value(self) -> 'FiniteField': + new_value = self.value.next_value() + # do modulo over n + while new_value.degree() >= self.n: + new_value = new_value % self.irreducible_polynomial + return FiniteField(self.p, self.n, new_value, self.irreducible_polynomial) + + def field_property_check(func): + def wrapper(self: 'FiniteField', other: 'FiniteField') -> 'FiniteField': + if self.n != other.n: + raise ValueError("Fields must have the same degree") + if self.p != other.p: + raise ValueError("Fields must have the same prime modulus") + if self.irreducible_polynomial != other.irreducible_polynomial: + raise ValueError("Irreducible polynomials must be the same") + return func(self, other) + return wrapper + + @field_property_check + def __add__(self, other: 'FiniteField') -> 'FiniteField': + return FiniteField(self.p, self.n, (self.value + other.value)%self.irreducible_polynomial, self.irreducible_polynomial) + + @field_property_check + def __sub__(self, other: 'FiniteField') -> 'FiniteField': + return FiniteField(self.p, self.n, (self.value + other.additive_inverse()).value%self.irreducible_polynomial, self.irreducible_polynomial) + + @field_property_check + def __mul__(self, other: 'FiniteField') -> 'FiniteField': + return FiniteField(self.p, self.n, (self.value * other.value)%self.irreducible_polynomial, self.irreducible_polynomial) + + @field_property_check + def __truediv__(self, other: 'FiniteField') -> 'FiniteField': + return FiniteField(self.p, self.n, (self.value * other.multiplicative_inverse()).value%self.irreducible_polynomial, self.irreducible_polynomial) + + @field_property_check + def __eq__(self, other: 'FiniteField') -> bool: + return self.value == other.value + + @field_property_check + def __ne__(self, other: 'FiniteField') -> bool: + return self.value != other.value + + def __str__(self) -> str: + return f"FiniteField over GF({self.p}) of degree {self.n}: {self.value}" + + def as_vector(self) -> list[int]: + return [coefficient.value for coefficient in self.value.coefficients] + + def as_number(self) -> int: + return self.value.as_number() + + def as_polynomial(self) -> Polynomial: + return self.value + +``` + +## Linear codes + +## Local recoverable codes \ No newline at end of file diff --git a/content/CSE5313/_meta.js b/content/CSE5313/_meta.js index c89ff19..4d7622b 100644 --- a/content/CSE5313/_meta.js +++ b/content/CSE5313/_meta.js @@ -3,6 +3,7 @@ export default { "---":{ type: 'separator' }, + Exam_reviews: "Exam reviews", CSE5313_L1: "CSE5313 Coding and information theory for data science (Lecture 1)", CSE5313_L2: "CSE5313 Coding and information theory for data science (Lecture 2)", CSE5313_L3: "CSE5313 Coding and information theory for data science (Lecture 3)",