Source code for kaira.models.fec.encoders.repetition_code

"""Repetition coding module for forward error correction.

This module implements repetition coding for binary data transmission, a simple error correction
technique where each bit is repeated multiple times. For decoding, a majority vote scheme is used
to determine the most likely transmitted bit value :cite:`lin2004error,moon2005error`.

Repetition coding provides a straightforward way to improve reliability at the expense of rate,
making it suitable for educational purposes and systems with strict reliability requirements but
modest rate requirements.

As a special case of linear block codes, repetition codes have a generator matrix consisting
of a single row of all ones, and a check matrix with (n-1) rows forming a basis for the
orthogonal complement of the all-ones vector :cite:`richardson2008modern`.
"""

from typing import Any

import torch

from kaira.models.registry import ModelRegistry

from .linear_block_code import LinearBlockCodeEncoder


def _binomial_coefficient(n: int, k: int) -> int:
    """Calculate binomial coefficient (n choose k) using PyTorch.

    Args:
        n: Total number of items
        k: Number of items to choose

    Returns:
        Binomial coefficient n choose k
    """
    if k > n or k < 0:
        return 0
    if k == 0 or k == n:
        return 1

    # Use the multiplicative formula to avoid overflow
    # C(n,k) = n! / (k! * (n-k)!) = (n * (n-1) * ... * (n-k+1)) / (k * (k-1) * ... * 1)
    k = min(k, n - k)  # Take advantage of symmetry
    result = 1
    for i in range(k):
        result = result * (n - i) // (i + 1)
    return result


[docs] @ModelRegistry.register_model("repetition_encoder") class RepetitionCodeEncoder(LinearBlockCodeEncoder): """Encoder for repetition coding that extends LinearBlockCodeEncoder. This encoder implements a repetition code, which is a special case of linear block codes where each bit is repeated n times. A repetition code has the following properties: - Length: n (the repetition factor) - Dimension: k = 1 (one information bit produces n coded bits) - Redundancy: r = n - 1 (number of redundant bits) - Minimum distance: d = n (can correct up to ⌊(n-1)/2⌋ errors) Its dual is the single parity-check code. The generator matrix is a single row of all ones [1, 1, ..., 1]. Attributes: repetition_factor (int): The length n of the code. Must be a positive integer. Args: repetition_factor (int): Number of times to repeat each bit Examples: >>> import torch >>> encoder = RepetitionCodeEncoder(repetition_factor=5) >>> encoder.code_length, encoder.code_dimension, encoder.redundancy (5, 1, 4) >>> encoder.generator_matrix tensor([[1., 1., 1., 1., 1.]]) >>> encoder(torch.tensor([[1.]])) tensor([[1., 1., 1., 1., 1.]]) """
[docs] def __init__(self, repetition_factor: int = 3, **kwargs: Any): """Initialize the repetition encoder. Args: repetition_factor: Number of times to repeat each bit. Must be a positive integer. **kwargs: Variable keyword arguments passed to the base class. Raises: ValueError: If repetition_factor is less than 1. """ if repetition_factor < 1: raise ValueError("Repetition factor must be a positive integer") # Create the generator matrix for a repetition code: [1, 1, ..., 1] generator_matrix = torch.ones((1, repetition_factor), dtype=torch.float32) # Remove generator_matrix from kwargs if it exists to avoid duplicate kwargs_copy = kwargs.copy() if "generator_matrix" in kwargs_copy: del kwargs_copy["generator_matrix"] # Initialize the LinearBlockCodeEncoder parent with this generator matrix super().__init__(generator_matrix=generator_matrix, **kwargs_copy) # Store repetition factor as an attribute self.repetition_factor = repetition_factor
[docs] def coset_leader_weight_distribution(self) -> torch.Tensor: """Calculate the coset leader weight distribution of the repetition code. For a repetition code of length n, the coset leader weight distribution is given by the binomial coefficients C(n,w) for w from 0 to ⌊n/2⌋, with a special case for n/2 when n is even. Returns: Tensor containing the coset leader weight distribution """ n = self.repetition_factor distribution = torch.zeros(n + 1, dtype=torch.int64) # Fill in the distribution values for w in range((n + 1) // 2): distribution[w] = _binomial_coefficient(n, w) # Special case when n is even if n % 2 == 0: distribution[n // 2] = _binomial_coefficient(n, n // 2) // 2 return distribution
def __repr__(self) -> str: """Return a string representation of the object. Returns: String representation with key parameters """ return f"{self.__class__.__name__}(repetition_factor={self.repetition_factor})"